7

I am using Spring's MappingJacksonHttpMessageConverter to convert JSON message to object in my controller.

<bean id="jsonConverter"
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="prefixJson" value="false" />
    <property name="supportedMediaTypes" value="application/json" />
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jsonConverter" />
        </list>
    </property>
</bean>

For fields that are declared as ArrayList, if the json message contains a String instead, the following exception will be thrown:

org.springframework.http.converter.HttpMessageNotReadableException: 
 Could not read JSON: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token

An example would be the class definition below:

public class Product {
   private String name;
   private List<String> images;
}

Where the incoming Json is:

{name:"Widget", images:"image1.jpg"}

AS you can see, this will produce the exception since image is expected to be an array.

I would like to make custom deserializer which is a bit more tolerant. If deserialization fails, create a ArrayList of a single element from the String. How would I go about injecting this into the MappingJacksonHttpMessageConverter or ObjectMapper?

I am not looking to use annotation to mark each and every ArrayList field so a custom deserialize could be used. I am looking for a way to overwrite the default deserializer to preform this function.

4
  • What is the original string you're trying to deserialize? Commented Apr 20, 2012 at 14:46
  • say it is {product: "1234"} instead of {product: ["1234"]}
    – ltfishie
    Commented Apr 20, 2012 at 15:06
  • and how are you trying to deserialize it? can you post some code? Commented Apr 20, 2012 at 15:10
  • I am using Spring MappingJacksonHttpMessageConverter to deserialize it. I will post my configuration.
    – ltfishie
    Commented Apr 20, 2012 at 17:33

2 Answers 2

16

Check out this article describing how to use the features of the jackson objectMapper to accomplish this.

https://github.com/FasterXML/jackson-dataformat-xml/issues/21

For me adding the following solved this issue

jsonMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
2
  • 4
    or in version 2 jsonMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); Commented Feb 3, 2013 at 8:37
  • 4
    Christ, why was this so hard to find online? This is the solution I have been searching for -- thank you.
    – Ryan
    Commented Jun 5, 2014 at 6:51
2

As far as I see the incoming JSON doesn't contain any array. The question is: is "images" supposed to be separated or it contains a single image? Let's assume they are comma separated:

public class Product {
   private String name;
   private List<String> images;

   @JsonProperty("images")
   public String getImagesAsString() {
      StringBuilder sb = new StringBuilder();
      for (String img : images) {
          if (sb.length() > 0) sb.append(',');
          sb.append(img);
      }
      return sb.toString();
   }

   public void setImagesAsString(String img) {
       this.images = Arrays.asList(img.split(","));
   }

   @JsonIgnore
   public List<String> getImages() {
       return images;
   }
}
2
  • Thanks for you answer. Sorry if i did not make it clear, but what i am trying to do is to make parsing a little more tolerant. I also want to apply this to the default parsing behavior so I do not need to use annotations or create an second setter method for every field.
    – ltfishie
    Commented Apr 23, 2012 at 14:41
  • The other option is to make the images field to be a plain string (if it contains a single image), or change the format of JSON string to send an array instead of a string. Commented Apr 23, 2012 at 17:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.