Processor Class — spring-boot Architecture
Architecture documentation for the Processor class in BindableRuntimeHintsRegistrar.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java lines 149–334
private static final class Processor {
private final Class<?> type;
private final @Nullable Constructor<?> bindConstructor;
private final BeanProperties bean;
private final Set<Class<?>> seen;
Processor(Bindable<?> bindable) {
this(bindable, false, new HashSet<>());
}
private Processor(Bindable<?> bindable, boolean nestedType, Set<Class<?>> seen) {
this.type = getRawClass(bindable);
this.bindConstructor = (bindable.getBindMethod() != BindMethod.JAVA_BEAN)
? BindConstructorProvider.DEFAULT.getBindConstructor(getBindableType(bindable), nestedType) : null;
this.bean = JavaBeanBinder.BeanProperties.of(bindable);
this.seen = seen;
}
private static Class<?> getBindableType(Bindable<?> bindable) {
Class<?> resolved = bindable.getType().resolve();
Assert.state(resolved != null, "'resolved' must not be null");
return resolved;
}
private static Class<?> getRawClass(Bindable<?> bindable) {
Class<?> rawClass = bindable.getType().getRawClass();
Assert.state(rawClass != null, "'rawClass' must not be null");
return rawClass;
}
void process(ReflectionHints hints) {
if (this.seen.contains(this.type)) {
return;
}
this.seen.add(this.type);
handleConstructor(hints);
if (this.bindConstructor != null) {
handleValueObjectProperties(hints);
}
else if (this.bean != null && !this.bean.getProperties().isEmpty()) {
handleJavaBeanProperties(hints);
}
}
private void handleConstructor(ReflectionHints hints) {
if (this.bindConstructor != null) {
if (KotlinDetector.isKotlinType(this.bindConstructor.getDeclaringClass())) {
KotlinDelegate.handleConstructor(hints, this.bindConstructor);
}
else {
hints.registerConstructor(this.bindConstructor, ExecutableMode.INVOKE);
}
return;
}
Arrays.stream(this.type.getDeclaredConstructors())
.filter(this::hasNoParameters)
.findFirst()
.ifPresent((constructor) -> hints.registerConstructor(constructor, ExecutableMode.INVOKE));
}
private boolean hasNoParameters(Constructor<?> candidate) {
return candidate.getParameterCount() == 0;
}
private void handleValueObjectProperties(ReflectionHints hints) {
Assert.state(this.bindConstructor != null, "'bindConstructor' must not be null");
for (int i = 0; i < this.bindConstructor.getParameterCount(); i++) {
String propertyName = this.bindConstructor.getParameters()[i].getName();
ResolvableType propertyType = ResolvableType.forConstructorParameter(this.bindConstructor, i);
handleProperty(hints, propertyName, propertyType);
}
}
private void handleJavaBeanProperties(ReflectionHints hints) {
Map<String, BeanProperty> properties = this.bean.getProperties();
properties.forEach((name, property) -> {
Method getter = property.getGetter();
if (getter != null) {
hints.registerMethod(getter, ExecutableMode.INVOKE);
}
Method setter = property.getSetter();
if (setter != null) {
hints.registerMethod(setter, ExecutableMode.INVOKE);
}
Field field = property.getField();
if (field != null) {
hints.registerField(field);
}
handleProperty(hints, name, property.getType());
});
}
private void handleProperty(ReflectionHints hints, String propertyName, ResolvableType propertyType) {
Class<?> propertyClass = propertyType.resolve();
if (propertyClass == null) {
return;
}
if (propertyClass.equals(this.type)) {
return; // Prevent infinite recursion
}
Class<?> componentType = getComponentClass(propertyType);
if (componentType != null) {
// Can be a list of simple types
if (!isJavaType(componentType)) {
processNested(componentType, hints);
}
}
else if (isNestedType(propertyName, propertyClass)) {
processNested(propertyClass, hints);
}
}
private void processNested(Class<?> type, ReflectionHints hints) {
new Processor(Bindable.of(type), true, this.seen).process(hints);
}
private @Nullable Class<?> getComponentClass(ResolvableType type) {
ResolvableType componentType = getComponentType(type);
if (componentType == null) {
return null;
}
if (isContainer(componentType)) {
// Resolve nested generics like Map<String, List<SomeType>>
return getComponentClass(componentType);
}
return componentType.toClass();
}
private @Nullable ResolvableType getComponentType(ResolvableType type) {
if (type.isArray()) {
return type.getComponentType();
}
if (isCollection(type)) {
return type.asCollection().getGeneric();
}
if (isMap(type)) {
return type.asMap().getGeneric(1);
}
return null;
}
private boolean isContainer(ResolvableType type) {
return type.isArray() || isCollection(type) || isMap(type);
}
private boolean isCollection(ResolvableType type) {
return Collection.class.isAssignableFrom(type.toClass());
}
private boolean isMap(ResolvableType type) {
return Map.class.isAssignableFrom(type.toClass());
}
/**
* Specify whether the specified property refer to a nested type. A nested type
* represents a sub-namespace that need to be fully resolved. Nested types are
* either inner classes or annotated with {@link NestedConfigurationProperty}.
* @param propertyName the name of the property
* @param propertyType the type of the property
* @return whether the specified {@code propertyType} is a nested type
*/
private boolean isNestedType(String propertyName, Class<?> propertyType) {
Class<?> declaringClass = propertyType.getDeclaringClass();
if (declaringClass != null && isNested(declaringClass, this.type)) {
return true;
}
Field field = ReflectionUtils.findField(this.type, propertyName);
return (field != null) && MergedAnnotations.from(field).isPresent(Nested.class);
}
private static boolean isNested(Class<?> type, Class<?> candidate) {
if (type.isAssignableFrom(candidate)) {
return true;
}
return (candidate.getDeclaringClass() != null && isNested(type, candidate.getDeclaringClass()));
}
private boolean isJavaType(Class<?> candidate) {
return candidate.getPackageName().startsWith("java.");
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free