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.

ltfishie
  • 2,917
  • 6
  • 41
  • 68

2 Answers2

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);
TooCool
  • 10,598
  • 15
  • 60
  • 85
Ryan
  • 176
  • 1
  • 3
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;
   }
}
Eugene Retunsky
  • 13,009
  • 4
  • 52
  • 55
  • 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 Apr 23 '12 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. – Eugene Retunsky Apr 23 '12 at 17:14