INT-4318: Register Jackson modules if available
JIRA: https://jira.spring.io/browse/INT-4318 Do not `ObjectMApper.findAndRegisterModules()` unconditionally. If there is no the target module library in classpath, we end up with the `NoClassDefFoundError` * Copy-paste the well-known modules registration logic from the `org.springframework.http.converter.json.Jackson2ObjectMapperBuilder` since we can't add `spring-web` dependency to the `SI-core`
This commit is contained in:
committed by
Gary Russell
parent
32fdd2119f
commit
a3160f80f6
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2016 the original author or authors.
|
* Copyright 2013-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -36,6 +36,7 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @param <J> - The expected type of Java Type representation.
|
* @param <J> - The expected type of Java Type representation.
|
||||||
*
|
*
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJacksonJsonObjectMapper<N, P, J> extends JsonObjectMapperAdapter<N, P>
|
public abstract class AbstractJacksonJsonObjectMapper<N, P, J> extends JsonObjectMapperAdapter<N, P>
|
||||||
@@ -51,6 +52,10 @@ public abstract class AbstractJacksonJsonObjectMapper<N, P, J> extends JsonObjec
|
|||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return this.classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T fromJson(Object json, Class<T> valueType) throws Exception {
|
public <T> T fromJson(Object json, Class<T> valueType) throws Exception {
|
||||||
return this.fromJson(json, this.constructType(valueType));
|
return this.fromJson(json, this.constructType(valueType));
|
||||||
|
|||||||
@@ -25,18 +25,22 @@ import java.net.URL;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.integration.mapping.support.JsonHeaders;
|
import org.springframework.integration.mapping.support.JsonHeaders;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.MapperFeature;
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jackson 2 JSON-processor (@link https://github.com/FasterXML) {@linkplain JsonObjectMapper} implementation.
|
* Jackson 2 JSON-processor (@link https://github.com/FasterXML)
|
||||||
|
* {@linkplain JsonObjectMapper} implementation.
|
||||||
* Delegates <code>toJson</code> and <code>fromJson</code>
|
* Delegates <code>toJson</code> and <code>fromJson</code>
|
||||||
* to the {@linkplain com.fasterxml.jackson.databind.ObjectMapper}
|
* to the {@linkplain com.fasterxml.jackson.databind.ObjectMapper}
|
||||||
* <p>
|
* <p>
|
||||||
@@ -44,13 +48,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link MapperFeature#DEFAULT_VIEW_INCLUSION} is disabled</li>
|
* <li>{@link MapperFeature#DEFAULT_VIEW_INCLUSION} is disabled</li>
|
||||||
* <li>{@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} is disabled</li>
|
* <li>{@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} is disabled</li>
|
||||||
* <li>{@link ObjectMapper#findAndRegisterModules()} is performed</li>
|
* <li>The well-known modules are registered through the classpath scan</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
* See {@code org.springframework.http.converter.json.Jackson2ObjectMapperBuilder}
|
||||||
|
* in the spring-web for more information.
|
||||||
|
*
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
* @author Vikas Prasad
|
* @author Vikas Prasad
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<JsonNode, JsonParser, JavaType> {
|
public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<JsonNode, JsonParser, JavaType> {
|
||||||
|
|
||||||
@@ -60,7 +68,7 @@ public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<Js
|
|||||||
this.objectMapper = new ObjectMapper();
|
this.objectMapper = new ObjectMapper();
|
||||||
this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
|
this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
|
||||||
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
this.objectMapper.findAndRegisterModules();
|
registerWellKnownModulesIfAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Jackson2JsonObjectMapper(ObjectMapper objectMapper) {
|
public Jackson2JsonObjectMapper(ObjectMapper objectMapper) {
|
||||||
@@ -68,6 +76,10 @@ public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<Js
|
|||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObjectMapper getObjectMapper() {
|
||||||
|
return this.objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toJson(Object value) throws Exception {
|
public String toJson(Object value) throws Exception {
|
||||||
return this.objectMapper.writeValueAsString(value);
|
return this.objectMapper.writeValueAsString(value);
|
||||||
@@ -138,4 +150,58 @@ public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<Js
|
|||||||
return this.objectMapper.constructType(type);
|
return this.objectMapper.constructType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void registerWellKnownModulesIfAvailable() {
|
||||||
|
try {
|
||||||
|
Class<? extends Module> jdk7Module = (Class<? extends Module>)
|
||||||
|
ClassUtils.forName("com.fasterxml.jackson.datatype.jdk7.Jdk7Module", getClassLoader());
|
||||||
|
this.objectMapper.registerModule(BeanUtils.instantiateClass(jdk7Module));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
// jackson-datatype-jdk7 not available
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<? extends Module> jdk8Module = (Class<? extends Module>)
|
||||||
|
ClassUtils.forName("com.fasterxml.jackson.datatype.jdk8.Jdk8Module", getClassLoader());
|
||||||
|
this.objectMapper.registerModule(BeanUtils.instantiateClass(jdk8Module));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
// jackson-datatype-jdk8 not available
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<? extends Module> javaTimeModule = (Class<? extends Module>)
|
||||||
|
ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", getClassLoader());
|
||||||
|
this.objectMapper.registerModule(BeanUtils.instantiateClass(javaTimeModule));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
// jackson-datatype-jsr310 not available
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joda-Time present?
|
||||||
|
if (ClassUtils.isPresent("org.joda.time.LocalDate", getClassLoader())) {
|
||||||
|
try {
|
||||||
|
Class<? extends Module> jodaModule = (Class<? extends Module>)
|
||||||
|
ClassUtils.forName("com.fasterxml.jackson.datatype.joda.JodaModule", getClassLoader());
|
||||||
|
this.objectMapper.registerModule(BeanUtils.instantiateClass(jodaModule));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
// jackson-datatype-joda not available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kotlin present?
|
||||||
|
if (ClassUtils.isPresent("kotlin.Unit", getClassLoader())) {
|
||||||
|
try {
|
||||||
|
Class<? extends Module> kotlinModule = (Class<? extends Module>)
|
||||||
|
ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", getClassLoader());
|
||||||
|
this.objectMapper.registerModule(BeanUtils.instantiateClass(kotlinModule));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
//jackson-module-kotlin not available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ import org.springframework.messaging.support.GenericMessage;
|
|||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import com.fasterxml.jackson.databind.DatabindContext;
|
import com.fasterxml.jackson.databind.DatabindContext;
|
||||||
import com.fasterxml.jackson.databind.DeserializationConfig;
|
import com.fasterxml.jackson.databind.DeserializationConfig;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.MapperFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.cfg.MapperConfig;
|
import com.fasterxml.jackson.databind.cfg.MapperConfig;
|
||||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||||
@@ -56,7 +54,7 @@ public final class JacksonJsonUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an {@link com.fasterxml.jackson.databind.ObjectMapper} if available,
|
* Return an {@link ObjectMapper} if available,
|
||||||
* supplied with Message specific serializers and deserializers.
|
* supplied with Message specific serializers and deserializers.
|
||||||
* Also configured to store typo info in the {@code @class} property.
|
* Also configured to store typo info in the {@code @class} property.
|
||||||
* @param trustedPackages the trusted Java packages for deserialization.
|
* @param trustedPackages the trusted Java packages for deserialization.
|
||||||
@@ -64,11 +62,9 @@ public final class JacksonJsonUtils {
|
|||||||
* @throws IllegalStateException if an implementation is not available.
|
* @throws IllegalStateException if an implementation is not available.
|
||||||
* @since 4.3.10
|
* @since 4.3.10
|
||||||
*/
|
*/
|
||||||
public static com.fasterxml.jackson.databind.ObjectMapper messagingAwareMapper(String... trustedPackages) {
|
public static ObjectMapper messagingAwareMapper(String... trustedPackages) {
|
||||||
if (JacksonPresent.isJackson2Present()) {
|
if (JacksonPresent.isJackson2Present()) {
|
||||||
ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
|
ObjectMapper mapper = new Jackson2JsonObjectMapper().getObjectMapper();
|
||||||
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
|
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
||||||
|
|
||||||
mapper.setDefaultTyping(new WhitelistTypeResolverBuilder(trustedPackages));
|
mapper.setDefaultTyping(new WhitelistTypeResolverBuilder(trustedPackages));
|
||||||
|
|
||||||
@@ -84,13 +80,14 @@ public final class JacksonJsonUtils {
|
|||||||
MutableMessageJacksonDeserializer mutableMessageDeserializer = new MutableMessageJacksonDeserializer();
|
MutableMessageJacksonDeserializer mutableMessageDeserializer = new MutableMessageJacksonDeserializer();
|
||||||
mutableMessageDeserializer.setMapper(mapper);
|
mutableMessageDeserializer.setMapper(mapper);
|
||||||
|
|
||||||
mapper.registerModule(new SimpleModule()
|
SimpleModule simpleModule = new SimpleModule()
|
||||||
.addSerializer(new MessageHeadersJacksonSerializer())
|
.addSerializer(new MessageHeadersJacksonSerializer())
|
||||||
.addDeserializer(GenericMessage.class, genericMessageDeserializer)
|
.addDeserializer(GenericMessage.class, genericMessageDeserializer)
|
||||||
.addDeserializer(ErrorMessage.class, errorMessageDeserializer)
|
.addDeserializer(ErrorMessage.class, errorMessageDeserializer)
|
||||||
.addDeserializer(AdviceMessage.class, adviceMessageDeserializer)
|
.addDeserializer(AdviceMessage.class, adviceMessageDeserializer)
|
||||||
.addDeserializer(MutableMessage.class, mutableMessageDeserializer)
|
.addDeserializer(MutableMessage.class, mutableMessageDeserializer);
|
||||||
);
|
|
||||||
|
mapper.registerModule(simpleModule);
|
||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
Reference in New Issue
Block a user