ParameterPropertyDescriptor Class — spring-boot Architecture
Architecture documentation for the ParameterPropertyDescriptor class in ParameterPropertyDescriptor.java from the spring-boot codebase.
Entity Profile
Source Code
configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ParameterPropertyDescriptor.java lines 39–216
abstract class ParameterPropertyDescriptor extends PropertyDescriptor {
private final VariableElement parameter;
ParameterPropertyDescriptor(String name, TypeMirror type, VariableElement parameter, TypeElement declaringElement,
ExecutableElement getter) {
super(name, type, declaringElement, getter);
this.parameter = parameter;
}
final VariableElement getParameter() {
return this.parameter;
}
@Override
protected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {
Object defaultValue = getDefaultValueFromAnnotation(environment, getParameter());
return (defaultValue != null) ? defaultValue
: getParameter().asType().accept(DefaultPrimitiveTypeVisitor.INSTANCE, null);
}
private Object getDefaultValueFromAnnotation(MetadataGenerationEnvironment environment, Element element) {
AnnotationMirror annotation = environment.getDefaultValueAnnotation(element);
List<String> defaultValue = getDefaultValue(environment, annotation);
if (defaultValue != null) {
TypeMirror specificType = determineSpecificType(environment);
try {
List<Object> coerced = defaultValue.stream().map((value) -> coerceValue(specificType, value)).toList();
return (coerced.size() != 1) ? coerced : coerced.get(0);
}
catch (IllegalArgumentException ex) {
environment.getMessager().printMessage(Kind.ERROR, ex.getMessage(), element, annotation);
}
}
return null;
}
@SuppressWarnings("unchecked")
private List<String> getDefaultValue(MetadataGenerationEnvironment environment, AnnotationMirror annotation) {
if (annotation == null) {
return null;
}
Map<String, Object> values = environment.getAnnotationElementValues(annotation);
return (List<String>) values.get("value");
}
private TypeMirror determineSpecificType(MetadataGenerationEnvironment environment) {
TypeMirror parameterType = getParameter().asType();
TypeMirror elementType = environment.getTypeUtils().extractElementType(parameterType);
parameterType = (elementType != null) ? elementType : parameterType;
PrimitiveType primitiveType = environment.getTypeUtils().getPrimitiveType(parameterType);
return (primitiveType != null) ? primitiveType : parameterType;
}
private Object coerceValue(TypeMirror type, String value) {
Object coercedValue = type.accept(DefaultValueCoercionTypeVisitor.INSTANCE, value);
return (coercedValue != null) ? coercedValue : value;
}
@Override
public boolean isProperty(MetadataGenerationEnvironment env) {
return !isNested(env); // We must be able to bind it to build the object.
}
/**
* Visitor that gets the default value for primitives.
*/
private static final class DefaultPrimitiveTypeVisitor extends TypeKindVisitor8<Object, Void> {
static final DefaultPrimitiveTypeVisitor INSTANCE = new DefaultPrimitiveTypeVisitor();
@Override
public Object visitPrimitiveAsBoolean(PrimitiveType type, Void parameter) {
return false;
}
@Override
public Object visitPrimitiveAsByte(PrimitiveType type, Void parameter) {
return (byte) 0;
}
@Override
public Object visitPrimitiveAsShort(PrimitiveType type, Void parameter) {
return (short) 0;
}
@Override
public Object visitPrimitiveAsInt(PrimitiveType type, Void parameter) {
return 0;
}
@Override
public Object visitPrimitiveAsLong(PrimitiveType type, Void parameter) {
return 0L;
}
@Override
public Object visitPrimitiveAsChar(PrimitiveType type, Void parameter) {
return null;
}
@Override
public Object visitPrimitiveAsFloat(PrimitiveType type, Void parameter) {
return 0F;
}
@Override
public Object visitPrimitiveAsDouble(PrimitiveType type, Void parameter) {
return 0D;
}
}
/**
* Visitor that gets the default using coercion.
*/
private static final class DefaultValueCoercionTypeVisitor extends TypeKindVisitor8<Object, String> {
static final DefaultValueCoercionTypeVisitor INSTANCE = new DefaultValueCoercionTypeVisitor();
private <T extends Number> T parseNumber(String value, Function<String, T> parser,
PrimitiveType primitiveType) {
try {
return parser.apply(value);
}
catch (NumberFormatException ex) {
throw new IllegalArgumentException(
String.format("Invalid %s representation '%s'", primitiveType, value));
}
}
@Override
public Object visitPrimitiveAsBoolean(PrimitiveType type, String value) {
return Boolean.parseBoolean(value);
}
@Override
public Object visitPrimitiveAsByte(PrimitiveType type, String value) {
return parseNumber(value, Byte::parseByte, type);
}
@Override
public Object visitPrimitiveAsShort(PrimitiveType type, String value) {
return parseNumber(value, Short::parseShort, type);
}
@Override
public Object visitPrimitiveAsInt(PrimitiveType type, String value) {
return parseNumber(value, Integer::parseInt, type);
}
@Override
public Object visitPrimitiveAsLong(PrimitiveType type, String value) {
return parseNumber(value, Long::parseLong, type);
}
@Override
public Object visitPrimitiveAsChar(PrimitiveType type, String value) {
if (value.length() > 1) {
throw new IllegalArgumentException(String.format("Invalid character representation '%s'", value));
}
return value;
}
@Override
public Object visitPrimitiveAsFloat(PrimitiveType type, String value) {
return parseNumber(value, Float::parseFloat, type);
}
@Override
public Object visitPrimitiveAsDouble(PrimitiveType type, String value) {
return parseNumber(value, Double::parseDouble, type);
}
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free