Refine unmapped property support

Replace `@UnmappedPropertyValue` with a `skip` attribute on
`@PropertyMapping` so that any default attribute value can be skipped.

Closes gh-6455
This commit is contained in:
Phillip Webb 2016-07-27 13:07:39 -07:00
parent ac1ad2a145
commit 5d9836b3b1
6 changed files with 51 additions and 45 deletions

View File

@ -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<Class<?>
PropertyMapping typeMapping, Map<String, Object> 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,

View File

@ -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;
}

View File

@ -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,
}

View File

@ -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;
/**

View File

@ -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.

View File

@ -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,