From 6ba7849094ccbf3321e01f2369fb5c12a3756f21 Mon Sep 17 00:00:00 2001 From: Vladimir Tsanev Date: Fri, 9 Jun 2017 11:09:52 +0300 Subject: [PATCH 1/4] Allow abstract serializers/deserializer in @JsonComponent Previously JsonComponentModule tried to instantiate all inner classes and failed with InstantiationException when the class is abstract and extends JsonSerializer/JsonDeserializer. With this change is now possible to have common logic inner abstract classes. See gh-9443 --- .../boot/jackson/JsonComponentModule.java | 6 ++++-- .../jackson/JsonComponentModuleTests.java | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java b/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java index 33f9041ca90..4467d24893e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java +++ b/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java @@ -16,6 +16,7 @@ package org.springframework.boot.jackson; +import java.lang.reflect.Modifier; import java.util.Map; import javax.annotation.PostConstruct; @@ -78,8 +79,9 @@ public class JsonComponentModule extends SimpleModule implements BeanFactoryAwar addDeserializerWithDeducedType((JsonDeserializer) bean); } for (Class innerClass : bean.getClass().getDeclaredClasses()) { - if (JsonSerializer.class.isAssignableFrom(innerClass) - || JsonDeserializer.class.isAssignableFrom(innerClass)) { + if (!Modifier.isAbstract(innerClass.getModifiers()) && + (JsonSerializer.class.isAssignableFrom(innerClass) + || JsonDeserializer.class.isAssignableFrom(innerClass))) { try { addJsonBean(innerClass.newInstance()); } diff --git a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java index 03d3b78d599..b3bd49028d4 100644 --- a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java @@ -59,6 +59,15 @@ public class JsonComponentModuleTests { context.close(); } + @Test + public void moduleShouldAllowInnerAbstractClasses() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + JsonComponentModule.class, ComponentWithInnerAbstractClass.class); + JsonComponentModule module = context.getBean(JsonComponentModule.class); + assertSerialize(module); + context.close(); + } + private void assertSerialize(Module module) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); @@ -85,4 +94,15 @@ public class JsonComponentModuleTests { } + @JsonComponent + static class ComponentWithInnerAbstractClass { + + private static abstract class AbstractSerializer extends NameAndAgeJsonComponent.Serializer { + + } + + static class ConcreteSerializer extends AbstractSerializer { + + } + } } From c5c6a526d3e6d0810e628a78dd4154483deae2e0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 15 Jun 2017 13:30:25 +0200 Subject: [PATCH 2/4] Polish "Allow abstract serializers/deserializer in @JsonComponent" Closes gh-9443 --- .../org/springframework/boot/jackson/JsonComponentModule.java | 2 +- .../springframework/boot/jackson/JsonComponentModuleTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java b/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java index 4467d24893e..aa2708b9d58 100644 --- a/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java +++ b/spring-boot/src/main/java/org/springframework/boot/jackson/JsonComponentModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. diff --git a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java index b3bd49028d4..b4dad22fd3d 100644 --- a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. From 31ee45bf36323be8761a4165e21bdab07752a427 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 15 Jun 2017 13:35:33 +0200 Subject: [PATCH 3/4] Polish --- .../jackson/JsonComponentModuleTests.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java index b4dad22fd3d..3f65dd9a20c 100644 --- a/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/jackson/JsonComponentModuleTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.jackson; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.After; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -31,32 +32,35 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class JsonComponentModuleTests { + private AnnotationConfigApplicationContext context; + + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } + } + @Test public void moduleShouldRegisterSerializers() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( - JsonComponentModule.class, OnlySerializer.class); - JsonComponentModule module = context.getBean(JsonComponentModule.class); + load(OnlySerializer.class); + JsonComponentModule module = this.context.getBean(JsonComponentModule.class); assertSerialize(module); - context.close(); } @Test public void moduleShouldRegisterDeserializers() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( - JsonComponentModule.class, OnlyDeserializer.class); - JsonComponentModule module = context.getBean(JsonComponentModule.class); + load(OnlyDeserializer.class); + JsonComponentModule module = this.context.getBean(JsonComponentModule.class); assertDeserialize(module); - context.close(); } @Test public void moduleShouldRegisterInnerClasses() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( - JsonComponentModule.class, NameAndAgeJsonComponent.class); - JsonComponentModule module = context.getBean(JsonComponentModule.class); + load(NameAndAgeJsonComponent.class); + JsonComponentModule module = this.context.getBean(JsonComponentModule.class); assertSerialize(module); assertDeserialize(module); - context.close(); } @Test @@ -68,6 +72,14 @@ public class JsonComponentModuleTests { context.close(); } + private void load(Class... configs) { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(configs); + ctx.register(JsonComponentModule.class); + ctx.refresh(); + this.context = ctx; + } + private void assertSerialize(Module module) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); From 5d69318e2d45f44f62fe2030d20ebba9cea4f665 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 15 Jun 2017 13:43:13 +0200 Subject: [PATCH 4/4] Add reference to SpringBootApplication in EnableAutoConfiguration Closes gh-9521 --- .../autoconfigure/EnableAutoConfiguration.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java index 95fcaa4cf46..bf2fcf78434 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java @@ -41,6 +41,9 @@ import org.springframework.core.io.support.SpringFactoriesLoader; * {@link TomcatEmbeddedServletContainerFactory} (unless you have defined your own * {@link EmbeddedServletContainerFactory} bean). *

+ * When using {@link SpringBootApplication}, the auto-configuration of the context is + * automatically enabled and adding this annotation has therefore no additional effect. + *

* Auto-configuration tries to be as intelligent as possible and will back-away as you * define more of your own configuration. You can always manually {@link #exclude()} any * configuration that you never want to apply (use {@link #excludeName()} if you don't @@ -48,11 +51,12 @@ import org.springframework.core.io.support.SpringFactoriesLoader; * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied * after user-defined beans have been registered. *

- * The package of the class that is annotated with {@code @EnableAutoConfiguration} has - * specific significance and is often used as a 'default'. For example, it will be used - * when scanning for {@code @Entity} classes. It is generally recommended that you place - * {@code @EnableAutoConfiguration} in a root package so that all sub-packages and classes - * can be searched. + * The package of the class that is annotated with {@code @EnableAutoConfiguration}, + * usually via {@code @SpringBootApplication}, has specific significance and is often used + * as a 'default'. For example, it will be used when scanning for {@code @Entity} classes. + * It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're + * not using {@code @SpringBootApplication}) in a root package so that all sub-packages + * and classes can be searched. *

* Auto-configuration classes are regular Spring {@link Configuration} beans. They are * located using the {@link SpringFactoriesLoader} mechanism (keyed against this class). @@ -66,6 +70,7 @@ import org.springframework.core.io.support.SpringFactoriesLoader; * @see ConditionalOnMissingBean * @see ConditionalOnClass * @see AutoConfigureAfter + * @see SpringBootApplication */ @SuppressWarnings("deprecation") @Target(ElementType.TYPE)