From 1f9a9cf404e452cf25fbe21931e0b35ef61dff1f Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 4 Apr 2016 08:54:08 +0200 Subject: [PATCH] Auto-detect Kotlin Jackson module Issue: SPR-14108 --- build.gradle | 1 + .../converter/json/Jackson2ObjectMapperBuilder.java | 13 +++++++++++++ .../json/Jackson2ObjectMapperFactoryBean.java | 1 + .../json/Jackson2ObjectMapperBuilderTests.java | 12 +++++++++--- .../json/Jackson2ObjectMapperFactoryBeanTests.java | 1 + 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 219f1604ae..4ec54a38ad 100644 --- a/build.gradle +++ b/build.gradle @@ -739,6 +739,7 @@ project("spring-web") { } testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}") testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jackson2Version}") + testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson2Version}") testRuntime("com.sun.mail:javax.mail:${javamailVersion}") } } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 282e386f6d..9c049eda15 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -75,6 +75,7 @@ import org.springframework.util.StringUtils; *
  • jackson-datatype-jdk8: support for other Java 8 types like {@link java.util.Optional}
  • *
  • jackson-datatype-jsr310: support for Java 8 Date & Time API types
  • *
  • jackson-datatype-joda: support for Joda-Time types
  • + *
  • jackson-module-kotlin: support for Kotlin classes and data classes
  • * * *

    Compatible with Jackson 2.6 and higher, as of Spring 4.3. @@ -747,6 +748,18 @@ public class Jackson2ObjectMapperBuilder { // jackson-datatype-joda not available } } + + // Kotlin present? + if (ClassUtils.isPresent("kotlin.Unit", this.moduleClassLoader)) { + try { + Class kotlinModule = (Class) + ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", this.moduleClassLoader); + objectMapper.registerModule(BeanUtils.instantiate(kotlinModule)); + } + catch (ClassNotFoundException ex) { + // jackson-module-kotlin not available + } + } } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java index 0ab52307e0..562ebbb360 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java @@ -116,6 +116,7 @@ import org.springframework.context.ApplicationContextAware; *

  • jackson-datatype-jdk8: support for other Java 8 types like {@link java.util.Optional}
  • *
  • jackson-datatype-jsr310: support for Java 8 Date & Time API types
  • *
  • jackson-datatype-joda: support for Joda-Time types
  • + *
  • jackson-module-kotlin: support for Kotlin classes and data classes
  • * * *

    In case you want to configure Jackson's {@link ObjectMapper} with a custom {@link Module}, diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java index 5af3eb5f4d..3f4e2257bf 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java @@ -65,6 +65,7 @@ import com.fasterxml.jackson.databind.ser.std.NumberSerializer; import com.fasterxml.jackson.databind.type.SimpleType; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import kotlin.ranges.IntRange; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Test; @@ -255,6 +256,10 @@ public class Jackson2ObjectMapperBuilderTests { Optional optional = Optional.of("test"); assertEquals("\"test\"", new String(objectMapper.writeValueAsBytes(optional), "UTF-8")); + + // Kotlin module + IntRange range = new IntRange(1, 3); + assertEquals("{\"start\":1,\"end\":3}", new String(objectMapper.writeValueAsBytes(range), "UTF-8")); } @Test // SPR-12634 @@ -328,8 +333,8 @@ public class Jackson2ObjectMapperBuilderTests { Class target = String.class; Class mixInSource = Object.class; - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().mixIn(target, - mixInSource).build(); + ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules() + .mixIn(target, mixInSource).build(); assertEquals(1, objectMapper.mixInCount()); assertSame(mixInSource, objectMapper.findMixInClassFor(target)); @@ -342,7 +347,8 @@ public class Jackson2ObjectMapperBuilderTests { Map, Class> mixIns = new HashMap, Class>(); mixIns.put(target, mixInSource); - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().mixIns(mixIns).build(); + ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules() + .mixIns(mixIns).build(); assertEquals(1, objectMapper.mixInCount()); assertSame(mixInSource, objectMapper.findMixInClassFor(target)); diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java index 005623f6d5..8d83c1189a 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java @@ -285,6 +285,7 @@ public class Jackson2ObjectMapperFactoryBeanTests { Map, Class> mixIns = new HashMap, Class>(); mixIns.put(target, mixinSource); + this.factory.setModules(Collections.emptyList()); this.factory.setMixIns(mixIns); this.factory.afterPropertiesSet(); ObjectMapper objectMapper = this.factory.getObject();