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:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user