2012-04-20 21 views
6

Estoy usando Spring's MappingJacksonHttpMessageConverter para convertir el mensaje JSON a objeto en mi controlador.Deserializar ArrayList desde String usando Jackson

<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> 

Para los campos que se declaran como ArrayList, si el mensaje JSON contiene una cadena en lugar, se lanzará la siguiente excepción:

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

Un ejemplo podría ser la definición de clase a continuación:

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

Cuando el JSON entrante es:

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

Como puede ver, esto producirá la excepción ya que se espera que la imagen sea una matriz.

Me gustaría hacer un deserializador personalizado que sea un poco más tolerante. Si falla la deserialización, crea una ArrayList de un solo elemento de String. ¿Cómo voy a inyectar esto en MappingJacksonHttpMessageConverter u ObjectMapper?

No estoy buscando utilizar la anotación para marcar todos y cada uno de los campos ArrayList para que se pueda utilizar una deserialización personalizada. Estoy buscando una manera de sobrescribir el deserializador predeterminado para preformar esta función.

+0

¿Cuál es la cadena original que está tratando de deserializar? –

+0

dicen que es {producto: "1234"} en lugar de {producto: ["1234"]} – ltfishie

+0

y ¿cómo intentas deserializarlo? ¿Puedes publicar algún código? –

Respuesta

14

Consulte este artículo que describe cómo usar las características de jackMap objectMapper para lograr esto.

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

Para mí, añadiendo la siguiente resolvieron este problema

jsonMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 
+4

o en la versión 2 jsonMapper.configure (DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); –

+3

Cristo, ¿por qué era tan difícil encontrarlo en línea? * Esta * es la solución que he estado buscando, gracias. – Ryan

1

Por lo que veo, el JSON entrante no contiene ninguna matriz. La pregunta es: ¿se supone que las "imágenes" están separadas o contiene una sola imagen? Supongamos que están separados por comas:

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; 
    } 
} 
+0

Gracias por su respuesta. Lo siento si no lo dejé en claro, pero lo que estoy tratando de hacer es hacer que el análisis sea un poco más tolerante. También quiero aplicar esto al comportamiento de análisis predeterminado, por lo que no necesito usar anotaciones ni crear un segundo método de establecimiento para cada campo. – ltfishie

+0

La otra opción es hacer que el campo 'images' sea una cadena simple (si contiene una sola imagen) o cambiar el formato de la cadena JSON para enviar una matriz en lugar de una cadena. –

Cuestiones relacionadas