Forma correcta de escribir JSON deserializer en primavera o extenderlo


Estoy tratando de escribir un deserializador JSON personalizado en primavera. Quiero usar serializador predeterminado para la mayor parte de los campos y usar un deserializador personalizado para algunas propiedades. Es posible? Estoy tratando de esta manera porque, la mayor parte de las propiedades son valores, por lo que para estos puedo dejar que Jackson use deserializer predeterminado; pero pocas propiedades son referencias, por lo que en el deserializer personalizado tengo que consultar una base de datos para el nombre de referencia y obtener el valor de referencia de la base de datos.

Voy a mostrar algún código si necesario.

Author: rajadilipkolli, 2012-07-07

3 answers

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

Clase a 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 deserializer

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: Alternativamente, puede ver este artículo que utiliza nuevas versiones de com.fasterxml.jackson.databind.JsonDeserializer.

 71
Author: fbrundu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-25 10:28:04

Estaba tratando de @Autowire un servicio administrado por resorte en mi Deserializer. Alguien me avisó a Jackson usando el operador new cuando invocaba los serializadores/deserializadores. Esto significaba que no había cableado automático de la instancia de Jackson de mi Deserializer. Así es como pude @Autowire mi clase de servicio en mi Deserializer:

Contexto.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 un frijol administrado por resorte, cableado automático funciona!

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: Aunque mi respuesta original funcionó para mí cuando escribí esto, la respuesta de @xi.lin es exactamente lo que se necesita. ¡Buen hallazgo!

 8
Author: Beez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-20 22:27:16

Con Resorte MVC 4.2.1.RELEASE, necesita usar las nuevas dependencias de Jackson2 como se muestra a continuación para que el Deserializador funcione.

No use esto

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

Usa esto en su 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 use com.fasterxml.jackson.databind.JsonDeserializer y com.fasterxml.jackson.databind.annotation.JsonDeserialize para la deserialización y no las clases de org.codehaus.jackson

 1
Author: VimalKumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-15 11:53:36