Imaginez que j'ai cette méthode annotée dans un Spring 3 @Controller
@RequestMapping("")
public @ResponseBody MyObject index(@RequestBody OtherObject obj) {
MyObject result = ...;
return result;
}
Mais je dois configurer le format de sortie JSON, comme si je le faisais:
ObjectMapper om = new ObjectMapper();
om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
om.getSerializationConfig()
.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
om.getSerializationConfig()
.set(SerializationConfig.Feature.INDENT_OUTPUT, false);
Est-il possible de configurer ce comportement?
J'ai trouvé quelques questions connexes, mais je ne sais pas trop comment les adapter à mon cas particulier:
Je vous remercie !
AngerClown m'a dirigé dans la bonne direction.
C'est ce que j'ai finalement fait, juste au cas où quelqu'un le trouverait utile.
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<!-- jackson configuration : https://stackoverflow.com/questions/3661769 -->
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonSerializationConfig" />
<property name="targetMethod" value="setSerializationInclusion" />
<property name="arguments">
<list>
<value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_DEFAULT</value>
</list>
</property>
</bean>
Je dois encore comprendre comment configurer les autres propriétés telles que:
om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
Pour les personnes qui utilisent Configuration Spring basée sur Java :
@Configuration
@ComponentScan(basePackages = "com.domain.sample")
@EnableWebMvc
public class SpringConfig extends WebMvcConfigurerAdapter {
....
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
converter.setObjectMapper(objectMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
....
}
J'utilise MappingJackson2HttpMessageConverter
- qui vient de plus rapide.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.1</version>
</dependency>
Si vous voulez utiliser le mappeur codehaus-jackson, utilisez plutôt celui-ci MappingJacksonHttpMessageConverter
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${codehaus.jackson.version}</version>
</dependency>
J'ai besoin de résoudre un problème très similaire, qui consiste à configurer Jackson Mapper pour "Ne pas sérialiser les valeurs nulles pour l'amour du Christ !!!".
Je ne voulais pas quitter mvc: balise pilotée par annotation, alors j'ai découvert comment configurer ObjectMapper de Jackson sans supprimer mvc: piloté par annotation et sans ajouter ContentNegotiatedViewResolver.
La belle chose est que vous n'avez pas à écrire de code Java vous-même!
Et voici la configuration XML (à ne pas confondre avec les différents espaces de noms des classes de Jackson, j'ai simplement utilisé la nouvelle bibliothèque Jakson 2.x ... la même chose devrait également fonctionner avec les bibliothèques Jackson 1.x):
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Pour Spring version 4.1.3+
J'ai essayé la solution de Jama, mais toutes les réponses ont ensuite été renvoyées avec le type de contenu 'application/json', y compris la page HTML générée principale.
Remplacer configureMessageConverters(...)
empêche le printemps de configurer les convertisseurs par défaut. Spring 4.1.3 permet de modifier les convertisseurs déjà configurés en remplaçantextendMessageConverters(...)
:
@Configuration
public class ConverterConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof AbstractJackson2HttpMessageConverter) {
AbstractJackson2HttpMessageConverter c = (AbstractJackson2HttpMessageConverter) converter;
ObjectMapper objectMapper = c.getObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
}
}
super.extendMessageConverters(converters);
}
}
voir
org.springframework..WebMvcConfigurationSupport#getMessageConverters()
voir
org.springframework..WebMvcConfigurationSupport#addDefaultHttpMessageConverters(...)
En spring3.2, une nouvelle solution est introduite par: http://static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/api/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.html , ci-dessous est mon exemple:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="featuresToEnable">
<array>
<util:constant static-field="com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES" />
</array>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
J'ai écrit mon propre FactoryBean qui instancie un ObjectMapper (version simplifiée):
public class ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>{
@Override
public ObjectMapper getObject() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
return mapper;
}
@Override
public Class<?> getObjectType() {
return ObjectMapper.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
Et l'utilisation dans la configuration de printemps:
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
Ne répond pas à la question, mais voici le meilleur résultat de Google.
Si quelqu'un vient ici et veut le faire pour le printemps 4 (comme cela m'est arrivé), vous pouvez utiliser l'annotation
@JsonInclude(Include.NON_NULL)
sur la classe de retour.
Jetez un coup d'œil à l'approche de Rick Hightower. Son approche évite de configurer ObjectMapper en tant que singleton et vous permet de filtrer la réponse JSON pour le même objet de différentes manières pour chaque méthode de requête.
http://www.jroller.com/RickHigh/entry/filtering_json_feeds_from_spring
Vous pouvez configurer ObjectMapper en tant que bean dans votre fichier XML Spring. Ce qui contient une référence à ObjectMapper est la classe MappingJacksonJsonView
. Vous devez ensuite attacher la vue à un ViewResolver.
Quelque chose comme ça devrait marcher:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="html" value="text/html" />
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="false" />
<property name="objectMapper" value="customObjectMapper" />
</bean>
</list>
</property>
</bean>
Où customObjectMapper
est défini ailleurs dans le fichier xml. Notez que vous pouvez directement définir les valeurs de la propriété Spring avec les définitions Enums Jackson; voir cette question .
En outre, ContentNegotiatedViewResolver n'est probablement pas requis, c'est simplement le code que j'utilise dans un projet existant.
Oui, mais que se passe-t-il si vous commencez à utiliser mixins par exemple, vous ne pouvez pas utiliser ObjectMapper en tant que singleton, car vous appliquerez la configuration globalement. Vous allez donc ajouter ou définir les classes mixin sur la même instance ObjectMapper?
Vous pouvez effectuer les opérations suivantes (version jackson <2):
Classe de mappeur personnalisé:
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
super.getSerializationConfig()
.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
super.getSerializationConfig()
.set(SerializationConfig.Feature.INDENT_OUTPUT, false);
}
}
Configuration de printemps:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="package.CustomObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>