2012-07-07 15 views
36

Estoy intentando escribir un deserializador JSON personalizado en Spring. Quiero usar el serializador predeterminado para la mayoría de las partes de los campos y usar un deserializador personalizado para algunas propiedades. ¿Es posible? Lo intento porque la mayoría de las propiedades son valores, por lo que puedo permitir que Jackson use el deserializador predeterminado; pero pocas propiedades son referencias, por lo que en el deserializador personalizado debo consultar una base de datos para obtener el nombre de referencia y obtener el valor de referencia de la base de datos.Forma correcta de escribir el deserializador JSON en Spring o ampliarlo

Voy a mostrar algunos códigos si es necesario.

+0

Para aclarar, ¿cómo ha de determinarse si un tratamiento personalizado se va a utilizar: por nombre del campo (eficacia), o por ¿Tipo de campo? –

+0

Disculpe, no vi este comentario @ProgrammerBruce ... Creo que, por tipo de campo ... – gc5

Respuesta

65

He buscado mucho y la mejor manera que he encontrado hasta ahora es en este article:

clase para serializar

package net.sghill.example; 

import net.sghill.example.UserDeserializer 
import net.sghill.example.UserSerializer 
import org.codehaus.jackson.map.annotate.JsonDeserialize; 
import org.codehaus.jackson.map.annotate.JsonSerialize; 

@JsonDeserialize(using = UserDeserializer.class) 
public class User { 
    private ObjectId id; 
    private String username; 
    private String password; 

    public User(ObjectId id, String username, String password) { 
     this.id = id; 
     this.username = username; 
     this.password = password; 
    } 

    public ObjectId getId()  { return id; } 
    public String getUsername() { return username; } 
    public String getPassword() { return password; } 
} 

clase deserializador

package net.sghill.example; 

import net.sghill.example.User; 
import org.codehaus.jackson.JsonNode; 
import org.codehaus.jackson.JsonParser; 
import org.codehaus.jackson.ObjectCodec; 
import org.codehaus.jackson.map.DeserializationContext; 
import org.codehaus.jackson.map.JsonDeserializer; 

import java.io.IOException; 

public class UserDeserializer extends JsonDeserializer<User> { 

    @Override 
    public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { 
     ObjectCodec oc = jsonParser.getCodec(); 
     JsonNode node = oc.readTree(jsonParser); 
     return new User(null, node.get("username").getTextValue(), node.get("password").getTextValue()); 
    } 
} 

Editar: Como alternativa, puede mirar this article que utiliza nuevas versiones de com.fasterxml.jackson.databind.JsonDeserializer.

+43

¡Hola, ese es mi artículo! Me alegro de que lo haya encontrado útil :) – sghill

+0

¡Me salvó el día! Gracias. –

+0

En las nuevas versiones de jackson en la clase 'com.fasterxml.jackson.databind.JsonDeserializer', use' asText() 'en lugar de' getTextValue() 'para obtener el texto. ¡¡Gracias!! +1 ':)' – albciff

8

Estaba tratando de @Autowire un servicio administrado por Spring en mi Deserializer. Alguien me avisó a Jackson usando el operador new al invocar los serializadores/deserializadores. Esto significa que no hay auto-cableado de la instancia de Jackson de mi Deserializer. Así es como yo era capaz de @Autowire mi clase de servicio en mi Deserializer:

context.xml

<mvc:annotation-driven> 
    <mvc:message-converters> 
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
     <property name="objectMapper" ref="objectMapper" /> 
    </bean> 
    </mvc:message-converters> 
</mvc> 
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> 
    <!-- Add deserializers that require autowiring --> 
    <property name="deserializersByType"> 
     <map key-type="java.lang.Class"> 
      <entry key="com.acme.Anchor"> 
       <bean class="com.acme.AnchorDeserializer" /> 
      </entry> 
     </map> 
    </property> 
</bean> 

Ahora que mi Deserializer es una fábrica de frijol de primavera gestionados, auto-cableado!

AnchorDeserializer.java

public class AnchorDeserializer extends JsonDeserializer<Anchor> { 
    @Autowired 
    private AnchorService anchorService; 
    public Anchor deserialize(JsonParser parser, DeserializationContext context) 
      throws IOException, JsonProcessingException { 
     // Do stuff 
    } 
} 

AnchorService.java

@Service 
public class AnchorService {} 

actualización: Si bien mi respuesta original que funcionó para mí volver cuando escribí esto, @xi La respuesta de .lin es exactamente lo que se necesita. Buen hallazgo!

+1

Tu solución no me ha ayudado. Resolví este problema usando ** [SpringBeanAutowiringSupport] (http://docs.spring.io/spring/docs/2.5.6/api/org/springframework/web/context/support/SpringBeanAutowiringSupport.html) **. –

+4

Creo que también puede ver esto [referirse] (http://www.runningasroot.com/blog/2012/05/02/autowiring-jackson-deserializers-in-spring/) que usa 'HandlerInstantiator' para hacer esto. –

+0

Es interesante que este enfoque funcione para algunos y no para otros. El enfoque utilizado por @ PeterJurkovič no funcionó para mí, pero este sí lo hace. –

1

Con Spring MVC 4.2.1.RELEASE, debe usar las nuevas dependencias de Jackson2 como a continuación para que el Deserializer funcione.

no uso esta

<dependency> 
      <groupId>org.codehaus.jackson</groupId> 
      <artifactId>jackson-mapper-asl</artifactId> 
      <version>1.9.12</version> 
     </dependency> 

Use este lugar.

<dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-annotations</artifactId> 
      <version>2.2.2</version> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-core</artifactId> 
      <version>2.2.2</version> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-databind</artifactId> 
      <version>2.2.2</version> 
     </dependency> 

también utilizar com.fasterxml.jackson.databind.JsonDeserializer y com.fasterxml.jackson.databind.annotation.JsonDeserialize para la deserialización y no las clases de org.codehaus.jackson

Cuestiones relacionadas