提交 2fccf3ff 编写于 作者: S Sebastien Deleuze

Add support for autowiring Jackson handlers

This commit introduces the SpringHandlerInstantiator
class, a Jackson HandlerInstantiator that allows to autowire
Jackson handlers (JsonSerializer, JsonDeserializer, KeyDeserializer,
TypeResolverBuilder and TypeIdResolver) if needed.

SpringHandlerInstantiator is automatically used with
@EnableWebMvc and <mvc:annotation-driven />.

Issue: SPR-10768
上级 ea7f787a
......@@ -31,16 +31,20 @@ import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import javafx.application.Application;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
......@@ -94,6 +98,10 @@ public class Jackson2ObjectMapperBuilder {
private ClassLoader moduleClassLoader = getClass().getClassLoader();
private HandlerInstantiator handlerInstantiator;
private ApplicationContext applicationContext;
/**
* If set to {@code true}, an {@link XmlMapper} will be created using its
......@@ -379,6 +387,27 @@ public class Jackson2ObjectMapperBuilder {
return this;
}
/**
* Customize the construction of Jackson handlers ({@link JsonSerializer}, {@link JsonDeserializer},
* {@link KeyDeserializer}, {@code TypeResolverBuilder} and {@code TypeIdResolver}).
* @since 4.1.3
* @see Jackson2ObjectMapperBuilder#applicationContext(ApplicationContext)
*/
public Jackson2ObjectMapperBuilder handlerInstantiator(HandlerInstantiator handlerInstantiator) {
this.handlerInstantiator = handlerInstantiator;
return this;
}
/**
* Set the Spring {@link ApplicationContext} in order to autowire Jackson handlers ({@link JsonSerializer},
* {@link JsonDeserializer}, {@link KeyDeserializer}, {@code TypeResolverBuilder} and {@code TypeIdResolver}).
* @since 4.1.3
* @see SpringHandlerInstantiator
*/
public Jackson2ObjectMapperBuilder applicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
return this;
}
/**
* Build a new {@link ObjectMapper} instance.
......@@ -468,6 +497,12 @@ public class Jackson2ObjectMapperBuilder {
for (Class<?> target : this.mixIns.keySet()) {
objectMapper.addMixInAnnotations(target, this.mixIns.get(target));
}
if (this.handlerInstantiator != null) {
objectMapper.setHandlerInstantiator(this.handlerInstantiator);
}
else if (this.applicationContext != null) {
objectMapper.setHandlerInstantiator(new SpringHandlerInstantiator(this.applicationContext.getAutowireCapableBeanFactory()));
}
}
// Any change to this method should be also applied to spring-jms and spring-messaging
......
......@@ -26,16 +26,20 @@ import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} (default) or
......@@ -119,9 +123,11 @@ import org.springframework.beans.factory.InitializingBean;
* @author Brian Clozel
* @author Juergen Hoeller
* @author Tadaya Tsuyukubo
* @author Sebastien Deleuze
* @since 3.2
*/
public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, BeanClassLoaderAware, InitializingBean {
public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, BeanClassLoaderAware,
ApplicationContextAware, InitializingBean {
private final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
......@@ -336,6 +342,16 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
this.builder.findModulesViaServiceLoader(findModules);
}
/**
* Customize the construction of Jackson handlers ({@link JsonSerializer}, {@link JsonDeserializer},
* {@link KeyDeserializer}, {@code TypeResolverBuilder} and {@code TypeIdResolver}).
* @since 4.1.3
* @see Jackson2ObjectMapperFactoryBean#setApplicationContext(ApplicationContext)
*/
public void setHandlerInstantiator(HandlerInstantiator handlerInstantiator) {
this.builder.handlerInstantiator(handlerInstantiator);
}
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.builder.moduleClassLoader(beanClassLoader);
......@@ -353,6 +369,17 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
}
}
/**
* Set the builder {@link ApplicationContext} in order to autowire Jackson handlers ({@link JsonSerializer},
* {@link JsonDeserializer}, {@link KeyDeserializer}, {@code TypeResolverBuilder} and {@code TypeIdResolver}).
* @since 4.1.3
* @see Jackson2ObjectMapperBuilder#applicationContext(ApplicationContext)
* @see SpringHandlerInstantiator
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.builder.applicationContext(applicationContext);
}
/**
* Return the singleton ObjectMapper.
......
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.converter.json;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
/**
* Eventually get Jackson handler ({@link JsonSerializer}, {@link JsonDeserializer},
* {@link KeyDeserializer}, {@link TypeResolverBuilder}, {@link TypeIdResolver}) beans by
* type from Spring {@link ApplicationContext}. If no bean is found, the default behavior
* happen (calling no-argument constructor via reflection).
*
* @since 4.1.3
* @author Sebastien Deleuze
* @see Jackson2ObjectMapperBuilder#handlerInstantiator(HandlerInstantiator)
* @see HandlerInstantiator
*/
public class SpringHandlerInstantiator extends HandlerInstantiator {
private final AutowireCapableBeanFactory beanFactory;
/**
* Create a new SpringHandlerInstantiator for the given BeanFactory.
* @param beanFactory the target BeanFactory
*/
public SpringHandlerInstantiator(AutowireCapableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
@Override
public JsonSerializer<?> serializerInstance(SerializationConfig config,
Annotated annotated, Class<?> keyDeserClass) {
return (JsonSerializer<?>) this.beanFactory.createBean(keyDeserClass);
}
@Override
public JsonDeserializer<?> deserializerInstance(DeserializationConfig config,
Annotated annotated, Class<?> deserClass) {
return (JsonDeserializer<?>) this.beanFactory.createBean(deserClass);
}
@Override
public KeyDeserializer keyDeserializerInstance(DeserializationConfig config,
Annotated annotated, Class<?> serClass) {
return (KeyDeserializer) this.beanFactory.createBean(serClass);
}
@Override
public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config,
Annotated annotated, Class<?> resolverClass) {
return (TypeResolverBuilder<?>) this.beanFactory.createBean(resolverClass);
}
@Override
public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config,
Annotated annotated, Class<?> resolverClass) {
return (TypeIdResolver) this.beanFactory.createBean(resolverClass);
}
}
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.converter.json;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;
import com.fasterxml.jackson.databind.type.TypeFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* Test class for {@link SpringHandlerInstantiatorTests}.
*
* @author Sebastien Deleuze
*/
public class SpringHandlerInstantiatorTests {
private SpringHandlerInstantiator instantiator;
private ObjectMapper objectMapper;
@Before
public void setup() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("capitalizer", new RootBeanDefinition(Capitalizer.class));
instantiator = new SpringHandlerInstantiator(bf);
objectMapper = Jackson2ObjectMapperBuilder.json().handlerInstantiator(instantiator).build();
}
@Test
public void autowiredSerializer() throws JsonProcessingException {
User user = new User("bob");
String json = this.objectMapper.writeValueAsString(user);
assertEquals("{\"username\":\"BOB\"}", json);
}
@Test
public void autowiredDeserializer() throws IOException {
String json = "{\"username\":\"bob\"}";
User user = this.objectMapper.readValue(json, User.class);
assertEquals(user.getUsername(), "BOB");
}
@Test
public void autowiredKeyDeserializer() throws IOException {
String json = "{\"credentials\":{\"bob\":\"admin\"}}";
SecurityRegistry registry = this.objectMapper.readValue(json, SecurityRegistry.class);
assertTrue(registry.getCredentials().keySet().contains("BOB"));
assertFalse(registry.getCredentials().keySet().contains("bob"));
}
@Test
public void applicationContextAwaretypeResolverBuilder() throws JsonProcessingException {
this.objectMapper.writeValueAsString(new Group("authors"));
assertTrue(CustomTypeResolverBuilder.isAutowiredFiledInitialized);
}
@Test
public void applicationContextAwareTypeIdResolver() throws JsonProcessingException {
this.objectMapper.writeValueAsString(new Group("authors"));
assertTrue(CustomTypeIdResolver.isAutowiredFiledInitialized);
}
public static class UserDeserializer extends JsonDeserializer<User> {
@Autowired
private Capitalizer capitalizer;
@Override
public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
return new User(this.capitalizer.capitalize(node.get("username").asText()));
}
}
public static class UserSerializer extends JsonSerializer<User> {
@Autowired
private Capitalizer capitalizer;
@Override
public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("username", this.capitalizer.capitalize(user.getUsername()));
jsonGenerator.writeEndObject();
}
}
public static class UpperCaseKeyDeserializer extends KeyDeserializer {
@Autowired
private Capitalizer capitalizer;
@Override
public Object deserializeKey(String key, DeserializationContext context) throws IOException, JsonProcessingException {
return this.capitalizer.capitalize(key);
}
}
public static class CustomTypeResolverBuilder extends StdTypeResolverBuilder {
@Autowired
private Capitalizer capitalizer;
public static boolean isAutowiredFiledInitialized = false;
@Override
public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
isAutowiredFiledInitialized = (this.capitalizer != null);
return super.buildTypeSerializer(config, baseType, subtypes);
}
@Override
public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
return super.buildTypeDeserializer(config, baseType, subtypes);
}
}
public static class CustomTypeIdResolver implements TypeIdResolver {
@Autowired
private Capitalizer capitalizer;
public static boolean isAutowiredFiledInitialized = false;
public CustomTypeIdResolver() {
}
@Override
public String idFromValueAndType(Object o, Class<?> type) {
return type.getClass().getName();
}
@Override
public JsonTypeInfo.Id getMechanism() {
return JsonTypeInfo.Id.CUSTOM;
}
@Override
public JavaType typeFromId(String s) {
return TypeFactory.defaultInstance().constructFromCanonical(s);
}
@Override
public String idFromValue(Object value) {
isAutowiredFiledInitialized = (this.capitalizer != null);
return value.getClass().getName();
}
@Override
public void init(JavaType type) {
}
@Override
public String idFromBaseType() {
return null;
}
}
@JsonDeserialize(using = UserDeserializer.class)
@JsonSerialize(using = UserSerializer.class)
public static class User {
private String username;
public User() {
}
public User(String username) {
this.username = username;
}
public String getUsername() { return this.username; }
}
public static class SecurityRegistry {
@JsonDeserialize(keyUsing = UpperCaseKeyDeserializer.class)
private Map<String, String> credentials = new HashMap<>();
public void addCredential(String username, String credential) {
this.credentials.put(username, credential);
}
public Map<String, String> getCredentials() {
return credentials;
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type")
@JsonTypeResolver(CustomTypeResolverBuilder.class)
@JsonTypeIdResolver(CustomTypeIdResolver.class)
public static class Group {
private String name;
public Group(String name) {
this.name = name;
}
public Group() {
}
public String getType() {
return Group.class.getName();
}
}
public static class Capitalizer {
public String capitalize(String text) {
return text.toUpperCase();
}
}
}
......@@ -29,6 +29,7 @@ import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
......@@ -44,6 +45,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
......@@ -534,14 +536,21 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
if (jackson2XmlPresent) {
messageConverters.add(createConverterDefinition(MappingJackson2XmlHttpMessageConverter.class, source));
RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2XmlHttpMessageConverter.class, source);
GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
jacksonFactoryDef.getPropertyValues().add("createXmlMapper", true);
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
messageConverters.add(jacksonConverterDef);
}
else if (jaxb2Present) {
messageConverters.add(createConverterDefinition(Jaxb2RootElementHttpMessageConverter.class, source));
}
if (jackson2Present) {
messageConverters.add(createConverterDefinition(MappingJackson2HttpMessageConverter.class, source));
RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2HttpMessageConverter.class, source);
GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
messageConverters.add(jacksonConverterDef);
}
else if (gsonPresent) {
messageConverters.add(createConverterDefinition(GsonHttpMessageConverter.class, source));
......@@ -550,6 +559,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return messageConverters;
}
private GenericBeanDefinition createObjectMapperFactoryDefinition(Object source) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Jackson2ObjectMapperFactoryBean.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
return beanDefinition;
}
private RootBeanDefinition createConverterDefinition(Class<?> converterClass, Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass);
beanDefinition.setSource(source);
......
......@@ -25,6 +25,8 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.Source;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
......@@ -45,6 +47,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
......@@ -671,14 +674,16 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
}
if (jackson2XmlPresent) {
messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
messageConverters.add(new MappingJackson2HttpMessageConverter());
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
......
......@@ -21,7 +21,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.messaging.support.ImmutableMessageChannelInterceptor;
import org.w3c.dom.Element;
......@@ -386,8 +387,12 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition resolverDef = new RootBeanDefinition(DefaultContentTypeResolver.class);
resolverDef.getPropertyValues().add("defaultMimeType", MimeTypeUtils.APPLICATION_JSON);
jacksonConverterDef.getPropertyValues().add("contentTypeResolver", resolverDef);
// Use Jackson builder in order to have JSR-310 and Joda-Time modules registered automatically
jacksonConverterDef.getPropertyValues().add("objectMapper", Jackson2ObjectMapperBuilder.json().build());
// Use Jackson factory in order to have JSR-310 and Joda-Time modules registered automatically
GenericBeanDefinition jacksonFactoryDef = new GenericBeanDefinition();
jacksonFactoryDef.setBeanClass(Jackson2ObjectMapperFactoryBean.class);
jacksonFactoryDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
jacksonFactoryDef.setSource(source);
jacksonConverterDef.getPropertyValues().add("objectMapper", jacksonFactoryDef);
converters.add(jacksonConverterDef);
}
}
......
......@@ -138,7 +138,8 @@ public abstract class WebSocketMessageBrokerConfigurationSupport extends Abstrac
protected MappingJackson2MessageConverter createJacksonConverter() {
MappingJackson2MessageConverter messageConverter = super.createJacksonConverter();
// Use Jackson builder in order to have JSR-310 and Joda-Time modules registered automatically
messageConverter.setObjectMapper(Jackson2ObjectMapperBuilder.json().build());
messageConverter.setObjectMapper(Jackson2ObjectMapperBuilder.json()
.applicationContext(this.getApplicationContext()).build());
return messageConverter;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册