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;
|
package org.springframework.boot.test.autoconfigure.properties;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -110,33 +109,32 @@ public class AnnotationsPropertySource extends EnumerablePropertySource<Class<?>
|
|||||||
PropertyMapping typeMapping, Map<String, Object> properties) {
|
PropertyMapping typeMapping, Map<String, Object> properties) {
|
||||||
PropertyMapping attributeMapping = AnnotationUtils.getAnnotation(attribute,
|
PropertyMapping attributeMapping = AnnotationUtils.getAnnotation(attribute,
|
||||||
PropertyMapping.class);
|
PropertyMapping.class);
|
||||||
if (isMapped(typeMapping, attributeMapping)) {
|
SkipPropertyMapping skip = getMappingType(typeMapping, attributeMapping);
|
||||||
String name = getName(typeMapping, attributeMapping, attribute);
|
if (skip == SkipPropertyMapping.YES) {
|
||||||
ReflectionUtils.makeAccessible(attribute);
|
return;
|
||||||
Object value = ReflectionUtils.invokeMethod(attribute, annotation);
|
}
|
||||||
if (isValueMapped(value)) {
|
String name = getName(typeMapping, attributeMapping, attribute);
|
||||||
putProperties(name, value, properties);
|
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) {
|
PropertyMapping attributeMapping) {
|
||||||
if (attributeMapping != null) {
|
if (attributeMapping != null) {
|
||||||
return attributeMapping.map();
|
return attributeMapping.skip();
|
||||||
}
|
}
|
||||||
return (typeMapping != null && typeMapping.map());
|
if (typeMapping != null) {
|
||||||
}
|
return typeMapping.skip();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return SkipPropertyMapping.YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getName(PropertyMapping typeMapping, PropertyMapping attributeMapping,
|
private String getName(PropertyMapping typeMapping, PropertyMapping attributeMapping,
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import org.springframework.test.context.TestPropertySource;
|
|||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
* @see AnnotationsPropertySource
|
* @see AnnotationsPropertySource
|
||||||
* @see UnmappedPropertyValue
|
|
||||||
* @see TestPropertySource
|
* @see TestPropertySource
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@@ -64,11 +63,11 @@ public @interface PropertyMapping {
|
|||||||
String value() default "";
|
String value() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if mapping should occur. When specified at the type-level indicates if
|
* Determines if mapping should be skipped. When specified at the type-level indicates
|
||||||
* mapping should occur by default or not. When used at the attribute-level, overrides
|
* if skipping should occur by default or not. When used at the attribute-level,
|
||||||
* the type-level default.
|
* overrides the type-level default.
|
||||||
* @return if mapping should occur
|
* @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;
|
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
|
* Enum used to control when {@link PropertyMapping} is skipped.
|
||||||
* {@link PropertyMapping @PropertyMapping} annotation.
|
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
* @see PropertyMapping
|
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
public enum SkipPropertyMapping {
|
||||||
@Target({ ElementType.FIELD })
|
|
||||||
public @interface UnmappedPropertyValue {
|
/**
|
||||||
|
* 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.autoconfigure.ImportAutoConfiguration;
|
||||||
import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
|
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.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
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.
|
* How {@link MvcResult} information should be printed after each MockMVC invocation.
|
||||||
* @return how information is printed
|
* @return how information is printed
|
||||||
*/
|
*/
|
||||||
|
@PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE)
|
||||||
MockMvcPrint print() default MockMvcPrint.DEFAULT;
|
MockMvcPrint print() default MockMvcPrint.DEFAULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.boot.test.autoconfigure.web.servlet;
|
package org.springframework.boot.test.autoconfigure.web.servlet;
|
||||||
|
|
||||||
import org.springframework.boot.test.autoconfigure.properties.UnmappedPropertyValue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MVC print options specified from {@link AutoConfigureMockMvc}.
|
* 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
|
* Use the default print setting ({@code MockMvcPrint.SYSTEM_OUT} unless explicitly
|
||||||
* overridden).
|
* overridden).
|
||||||
*/
|
*/
|
||||||
@UnmappedPropertyValue DEFAULT,
|
DEFAULT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log MVC interactions at the {@code DEBUG} level.
|
* Log MVC interactions at the {@code DEBUG} level.
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ public class AnnotationsPropertySourceTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@PropertyMapping(map = false)
|
@PropertyMapping(skip = SkipPropertyMapping.YES)
|
||||||
static @interface NotMappedAtTypeLevelAnnotation {
|
static @interface NotMappedAtTypeLevelAnnotation {
|
||||||
|
|
||||||
@PropertyMapping
|
@PropertyMapping
|
||||||
@@ -283,7 +283,7 @@ public class AnnotationsPropertySourceTests {
|
|||||||
|
|
||||||
String value();
|
String value();
|
||||||
|
|
||||||
@PropertyMapping(map = false)
|
@PropertyMapping(skip = SkipPropertyMapping.YES)
|
||||||
String ignore() default "xyz";
|
String ignore() default "xyz";
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -362,7 +362,9 @@ public class AnnotationsPropertySourceTests {
|
|||||||
static @interface AttributeWithAliasAnnotation {
|
static @interface AttributeWithAliasAnnotation {
|
||||||
|
|
||||||
@AliasFor(annotation = AliasedAttributeAnnotation.class, attribute = "value")
|
@AliasFor(annotation = AliasedAttributeAnnotation.class, attribute = "value")
|
||||||
String value() default "foo";
|
String value()
|
||||||
|
|
||||||
|
default "foo";
|
||||||
|
|
||||||
String someOtherAttribute() default "shouldNotBeMapped";
|
String someOtherAttribute() default "shouldNotBeMapped";
|
||||||
|
|
||||||
@@ -410,13 +412,14 @@ public class AnnotationsPropertySourceTests {
|
|||||||
@PropertyMapping("testenum")
|
@PropertyMapping("testenum")
|
||||||
static @interface EnumAnnotation {
|
static @interface EnumAnnotation {
|
||||||
|
|
||||||
EnumItem value();
|
@PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE)
|
||||||
|
EnumItem value() default EnumItem.DEFAULT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EnumItem {
|
enum EnumItem {
|
||||||
|
|
||||||
@UnmappedPropertyValue DEFAULT,
|
DEFAULT,
|
||||||
|
|
||||||
ONE,
|
ONE,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user