Search code examples
javajsonspring-bootjacksonjackson2

Deserializing using Jackson2 in Springboot an application/json response that is just "A String"


I'm calling an external API in my Springboot application and using MappingJackson2HttpMessageConverter to convert the application/json response but i'm running into issues as the response is just "Some message indicating success/failure" instead of a more typical JSON object like { 'property': 'value' }.

The error i'm specifically getting is:

JSON parse error: Cannot construct instance of `<custom class>` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Bundle is not available'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `<custom class>` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Bundle is not available')\n at [Source: (ByteArrayInputStream); line: 1, column: 1]

Just for reference, my code for configuring the JSON deserializer is something like:

public List<HttpMessageConverters<?>> getConverters() {
    List<HttpMessageConverter<?>> converters = new ArrayList<>();
    
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
    converters.add(converter);

    return converters;
}

I'm wondering how I would configure the MappingJackson2HttpMessageConverter to support bare strings?


Solution

  • So I solved this by writing my own message converter. Something like:

    class StringConverter extends AbstractJsonHttpMessageConverter {
        @Override
        protected Object readInternal(Type type, Reader reader) throws Exception {
            int currentChar;
            StringBuilder str = new StringBuilder();
            while((currentChar = reader.read()) != -1) {
                str.append((char) currentChar);
            }
            ObjectMapper om = new ObjectMapper();
            return objectMapper.readValue(str.toString(), Object.class);
        }
    
        @Override
        protected void writeInternal(Object o, Type type, Writer writer) throws Exception {
            // not required for my use case
        }
    }
    

    With this, String responses get stored in String classes and JSON responses get put into linked hash maps. If anyone has a better way of solving this, please post it as I'm sure this is far from the best way of doing it.