Question

Être encore un peu familier avec le printemps, j'ai rencontré un problème qui rend nécessaire la mise en œuvre d'un mon deserialzer personnalisé pour Jackson. La procédure est décrite dans un petit tutoriel , cependant, je suis coincé avec le printemps. Je ne comprends pas, où

 ObjectMapper mapper = new ObjectMapper();

dans Spring MVC est effectuée lorsque json est désérialise par une méthode d'une classe de contrôleur. Donc, je ne sais pas, ce qu'il faut faire pour remplacer le désérialiseur par défaut par un désérialiseur personnalisé.

Toutes les suggestions les bienvenus.

Était-ce utile?

La solution

Vous ne dites pas comment vous utilisez Jackson au printemps, donc je vais supposer que vous l'utilisez par <mvc:annotation-driven/> et les @RequestBody et / ou des annotations @ResponseBody.

L'une des choses que <mvc:annotation-driven/> fait est d'enregistrer un grain de AnnotationMethodHandlerAdapter qui est livré avec un certain nombre de grains de HttpMessageConverter préconfigurés, y compris MappingJacksonHttpMessageConverter, qui poignées de triage vers et à partir des classes de modèles Jackson annotées.

MappingJacksonHttpMessageConverter a une méthode setObjectMapper(), qui vous permet de remplacer la ObjectMapper par défaut. Mais depuis MappingJacksonHttpMessageConverter est créé dans les coulisses par <mvc:annotation-driven/>, vous ne pouvez pas y accéder.

Cependant, <mvc:annotation-driven/> est juste un raccourci pratique. Il est tout aussi valide pour déclarer votre propre grain de AnnotationMethodHandlerAdapter, injecter dans votre propre grain de MappingJacksonHttpMessageConverter (via la propriété messageConverters), et injecter votre propre ObjectMapper sur mesure dans cela.

Vous avez alors le problème de savoir comment construire un ObjectMapper sur mesure, car ce n'est pas une classe très Spring convivial. Je suggère d'écrire votre propre implémentation simple FactoryBean.

Vous finiriez avec quelque chose comme ceci:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
   <property name="messageConverters">
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
         <property name="objectMapper">
            <bean class="com.x.MyObjectMapperFactoryBean"/>
         </property>
      </bean>
   </property>
</bean>

Autres conseils

Une nouvelle façon de le faire au printemps 3.1:
http://magicmonster.com/kb/prg/java/spring/webmvc /mvc_spring_config_namespace.html

http : //blog.springsource.org/2011/02/21/spring-3-1-m1-mvc-namespace-enhancements-and-configuration/

vous permet de faire quelque chose comme ceci:

<mvc:annotation-driven>
      <mvc:message-converters>
          <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
              <property name="objectMapper" ref="customObjectMapper"/>
          </bean>
      </mvc:message-converters>
  </mvc:annotation-driven>

La solution référencée par Rakesh fonctionne probablement avec Spring MVC 3.0, mais avec 3,1 partie de l'infrastructure MVC a changé . Par conséquent, vous ne pouvez pas avoir un grain de AnnotationMethodHandlerAdapter enregistré dans votre contexte d'application et vous vous retrouverez avec un BeanCreationException au moment de l'initialisation.

Pour Spring MVC 3.1 l'élément mvc:annotation-driven va créer un RequestMappingHandlerAdapter pour vous, vous devez donc lier automatiquement ce type à la place. Il fournira un accès à la liste des inscrits HttpMessageConverters et vous permettent de définir la propriété ObjectMapper sur le MappingJacksonHttpMessageConverter. Cela nécessite également un léger changement dans le init. Procédé pour le type de la référence HttpMessageConverters.

Les regards de classe mis à jour comme:

@Component
public class JacksonFix {
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    private CustomObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        List<HttpMessageConverter<?>> messageConverters = requestMappingHandlerAdapter.getMessageConverters();
        for (HttpMessageConverter<?> messageConverter : messageConverters) {
            if (messageConverter instanceof MappingJacksonHttpMessageConverter) {
                MappingJacksonHttpMessageConverter m = (MappingJacksonHttpMessageConverter) messageConverter;
                m.setObjectMapper(objectMapper);
            }
        }
    }

    // this will exist due to the <mvc:annotation-driven/> bean
    @Autowired
    public void setRequestMappingHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
        this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
    }

    @Autowired
    public void setObjectMapper(CustomObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
}

UPDATE : Il se trouve la chose la plus facile absolue à voir avec Spring 3.1 est d'ajouter une configuration supplémentaire à votre configuration MVC:

<mvc:annotation-driven conversion-service="applicationConversionService">
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="objectMapper" ref="customObjectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Cela ajoutera une nouvelle instance de MappingJacksonHttpMessageConverter avec le ObjectMapper de coutume avant tout de la valeur par défaut HttpMessageConverters (qui sont encore présents en raison de register-defaults="true").

Dans mon cas (printemps 3.2.4 et 2.3.1 Jackson), configuration XML pour sérialiseur personnalisé:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

était à l'arrière de façon inexpliquée écrasé à défaut par quelque chose.

Cela a fonctionné pour moi:

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

Pas de configuration XML (<mvc:message-converters>(...)</mvc:message-converters>) est nécessaire dans ma solution.

Je voudrais savoir Spring MVC mieux, mais avec les implémentations JAX-RS comme Jersey et RESTeasy, un des fournisseurs de registres. Peut-être Spring fait quelque chose de semblable?

Les documents de ressort pour l'état MappingJacksonHttpMessageConverter:

2.4.5 MappingJacksonHttpMessageConverter

Une mise en œuvre HttpMessageConverter qui peut lire et écrire en utilisant JSON ObjectMapper Jackson JSON processeur. la cartographie JSON peut être personnalisé selon les besoins grâce à l'utilisation des annotations fournies Jackson. Quand un contrôle supplémentaire est nécessaire, une coutume ObjectMapper peut être injecté par la propriété ObjectMapper pour les cas où serializers JSON personnalisé / désérialiseurs doivent être fournis pour les types de spécifiques. Par défaut, ce support de conversion (application / JSON).

Impossible de vous venez autowire accès au ObjectMapper afin de modifier le comportement de ce?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top