From 5d9836b3b1bbbf01ae7e20482b8de4d32b9621ce Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 27 Jul 2016 13:07:39 -0700 Subject: [PATCH] Refine unmapped property support Replace `@UnmappedPropertyValue` with a `skip` attribute on `@PropertyMapping` so that any default attribute value can be skipped. Closes gh-6455 --- .../properties/AnnotationsPropertySource.java | 38 +++++++++---------- .../properties/PropertyMapping.java | 11 +++--- ...rtyValue.java => SkipPropertyMapping.java} | 28 ++++++++------ .../web/servlet/AutoConfigureMockMvc.java | 2 + .../web/servlet/MockMvcPrint.java | 4 +- .../AnnotationsPropertySourceTests.java | 13 ++++--- 6 files changed, 51 insertions(+), 45 deletions(-) rename spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/{UnmappedPropertyValue.java => SkipPropertyMapping.java} (63%) diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java index 1dea0bde5d..083250b901 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java @@ -17,7 +17,6 @@ package org.springframework.boot.test.autoconfigure.properties; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; @@ -110,33 +109,32 @@ public class AnnotationsPropertySource extends EnumerablePropertySource PropertyMapping typeMapping, Map properties) { PropertyMapping attributeMapping = AnnotationUtils.getAnnotation(attribute, PropertyMapping.class); - if (isMapped(typeMapping, attributeMapping)) { - String name = getName(typeMapping, attributeMapping, attribute); - ReflectionUtils.makeAccessible(attribute); - Object value = ReflectionUtils.invokeMethod(attribute, annotation); - if (isValueMapped(value)) { - putProperties(name, value, properties); + SkipPropertyMapping skip = getMappingType(typeMapping, attributeMapping); + if (skip == SkipPropertyMapping.YES) { + return; + } + String name = getName(typeMapping, attributeMapping, attribute); + ReflectionUtils.makeAccessible(attribute); + Object value = ReflectionUtils.invokeMethod(attribute, annotation); + if (skip == SkipPropertyMapping.ON_DEFAULT_VALUE) { + Object defaultValue = AnnotationUtils.getDefaultValue(annotation, + attribute.getName()); + if (ObjectUtils.nullSafeEquals(value, defaultValue)) { + return; } } + putProperties(name, value, properties); } - private boolean isMapped(PropertyMapping typeMapping, + private SkipPropertyMapping getMappingType(PropertyMapping typeMapping, PropertyMapping attributeMapping) { if (attributeMapping != null) { - return attributeMapping.map(); + return attributeMapping.skip(); } - return (typeMapping != null && typeMapping.map()); - } - - private boolean isValueMapped(Object value) { - if (value != null && value instanceof Enum) { - Field field = ReflectionUtils.findField(value.getClass(), - ((Enum) value).name()); - if (AnnotatedElementUtils.isAnnotated(field, UnmappedPropertyValue.class)) { - return false; - } + if (typeMapping != null) { + return typeMapping.skip(); } - return true; + return SkipPropertyMapping.YES; } private String getName(PropertyMapping typeMapping, PropertyMapping attributeMapping, diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/PropertyMapping.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/PropertyMapping.java index 817749d2bc..367a8a0eb2 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/PropertyMapping.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/PropertyMapping.java @@ -47,7 +47,6 @@ import org.springframework.test.context.TestPropertySource; * @author Phillip Webb * @since 1.4.0 * @see AnnotationsPropertySource - * @see UnmappedPropertyValue * @see TestPropertySource */ @Documented @@ -64,11 +63,11 @@ public @interface PropertyMapping { String value() default ""; /** - * Determines if mapping should occur. When specified at the type-level indicates if - * mapping should occur by default or not. When used at the attribute-level, overrides - * the type-level default. - * @return if mapping should occur + * Determines if mapping should be skipped. When specified at the type-level indicates + * if skipping should occur by default or not. When used at the attribute-level, + * overrides the type-level default. + * @return if mapping should be skipped */ - boolean map() default true; + SkipPropertyMapping skip() default SkipPropertyMapping.NO; } diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/UnmappedPropertyValue.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/SkipPropertyMapping.java similarity index 63% rename from spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/UnmappedPropertyValue.java rename to spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/SkipPropertyMapping.java index 59125660ad..77651bef2b 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/UnmappedPropertyValue.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/SkipPropertyMapping.java @@ -16,21 +16,27 @@ package org.springframework.boot.test.autoconfigure.properties; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - /** - * Indicates that a single value should not be mapped when referenced from a - * {@link PropertyMapping @PropertyMapping} annotation. + * Enum used to control when {@link PropertyMapping} is skipped. * * @author Phillip Webb * @since 1.4.0 - * @see PropertyMapping */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.FIELD }) -public @interface UnmappedPropertyValue { +public enum SkipPropertyMapping { + + /** + * Skip the mapping the property. + */ + YES, + + /** + * Skip mapping the property when the default attribute value is specified. + */ + ON_DEFAULT_VALUE, + + /** + * Don't skip mapping the property. + */ + NO, } diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java index 8d316a316c..e9dd050e0c 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java @@ -27,6 +27,7 @@ import org.openqa.selenium.WebDriver; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; +import org.springframework.boot.test.autoconfigure.properties.SkipPropertyMapping; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -57,6 +58,7 @@ public @interface AutoConfigureMockMvc { * How {@link MvcResult} information should be printed after each MockMVC invocation. * @return how information is printed */ + @PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE) MockMvcPrint print() default MockMvcPrint.DEFAULT; /** diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcPrint.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcPrint.java index efcc97bdce..363db81cc7 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcPrint.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcPrint.java @@ -16,8 +16,6 @@ package org.springframework.boot.test.autoconfigure.web.servlet; -import org.springframework.boot.test.autoconfigure.properties.UnmappedPropertyValue; - /** * MVC print options specified from {@link AutoConfigureMockMvc}. * @@ -30,7 +28,7 @@ public enum MockMvcPrint { * Use the default print setting ({@code MockMvcPrint.SYSTEM_OUT} unless explicitly * overridden). */ - @UnmappedPropertyValue DEFAULT, + DEFAULT, /** * Log MVC interactions at the {@code DEBUG} level. diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java index 183d8589b3..5aa7dff7a0 100644 --- a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java @@ -262,7 +262,7 @@ public class AnnotationsPropertySourceTests { } @Retention(RetentionPolicy.RUNTIME) - @PropertyMapping(map = false) + @PropertyMapping(skip = SkipPropertyMapping.YES) static @interface NotMappedAtTypeLevelAnnotation { @PropertyMapping @@ -283,7 +283,7 @@ public class AnnotationsPropertySourceTests { String value(); - @PropertyMapping(map = false) + @PropertyMapping(skip = SkipPropertyMapping.YES) String ignore() default "xyz"; } @@ -362,7 +362,9 @@ public class AnnotationsPropertySourceTests { static @interface AttributeWithAliasAnnotation { @AliasFor(annotation = AliasedAttributeAnnotation.class, attribute = "value") - String value() default "foo"; + String value() + + default "foo"; String someOtherAttribute() default "shouldNotBeMapped"; @@ -410,13 +412,14 @@ public class AnnotationsPropertySourceTests { @PropertyMapping("testenum") static @interface EnumAnnotation { - EnumItem value(); + @PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE) + EnumItem value() default EnumItem.DEFAULT; } enum EnumItem { - @UnmappedPropertyValue DEFAULT, + DEFAULT, ONE,