DefaultBindConstructorProvider Class — spring-boot Architecture
Architecture documentation for the DefaultBindConstructorProvider class in DefaultBindConstructorProvider.java from the spring-boot codebase.
Entity Profile
Source Code
core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DefaultBindConstructorProvider.java lines 40–214
class DefaultBindConstructorProvider implements BindConstructorProvider {
@Override
public @Nullable Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding) {
Constructors constructors = Constructors.getConstructors(bindable.getType().resolve(),
isNestedConstructorBinding);
if (constructors.getBind() != null && constructors.isDeducedBindConstructor()
&& !constructors.isImmutableType()) {
if (bindable.getValue() != null && bindable.getValue().get() != null) {
return null;
}
}
return constructors.getBind();
}
@Override
public @Nullable Constructor<?> getBindConstructor(Class<?> type, boolean isNestedConstructorBinding) {
Constructors constructors = Constructors.getConstructors(type, isNestedConstructorBinding);
return constructors.getBind();
}
/**
* Data holder for autowired and bind constructors.
*/
static final class Constructors {
private static final Constructors NONE = new Constructors(false, null, false, false);
private final boolean hasAutowired;
private final @Nullable Constructor<?> bind;
private final boolean deducedBindConstructor;
private final boolean immutableType;
private Constructors(boolean hasAutowired, @Nullable Constructor<?> bind, boolean deducedBindConstructor,
boolean immutableType) {
this.hasAutowired = hasAutowired;
this.bind = bind;
this.deducedBindConstructor = deducedBindConstructor;
this.immutableType = immutableType;
}
boolean hasAutowired() {
return this.hasAutowired;
}
@Nullable Constructor<?> getBind() {
return this.bind;
}
boolean isDeducedBindConstructor() {
return this.deducedBindConstructor;
}
boolean isImmutableType() {
return this.immutableType;
}
static Constructors getConstructors(@Nullable Class<?> type, boolean isNestedConstructorBinding) {
if (type == null) {
return NONE;
}
boolean hasAutowiredConstructor = isAutowiredPresent(type);
Constructor<?>[] candidates = getCandidateConstructors(type);
MergedAnnotations[] candidateAnnotations = getAnnotations(candidates);
boolean deducedBindConstructor = false;
boolean immutableType = type.isRecord();
Constructor<?> bind = getConstructorBindingAnnotated(type, candidates, candidateAnnotations);
if (bind == null && !hasAutowiredConstructor) {
bind = deduceBindConstructor(type, candidates);
deducedBindConstructor = bind != null;
}
if (bind == null && !hasAutowiredConstructor && isKotlinType(type)) {
bind = deduceKotlinBindConstructor(type);
deducedBindConstructor = bind != null;
}
if (bind != null || isNestedConstructorBinding) {
Assert.state(!hasAutowiredConstructor,
() -> type.getName() + " declares @ConstructorBinding and @Autowired constructor");
}
return new Constructors(hasAutowiredConstructor, bind, deducedBindConstructor, immutableType);
}
private static boolean isAutowiredPresent(Class<?> type) {
if (Stream.of(type.getDeclaredConstructors())
.map(MergedAnnotations::from)
.anyMatch((annotations) -> annotations.isPresent(Autowired.class))) {
return true;
}
Class<?> userClass = ClassUtils.getUserClass(type);
return (userClass != type) && isAutowiredPresent(userClass);
}
private static Constructor<?>[] getCandidateConstructors(Class<?> type) {
if (isInnerClass(type)) {
return new Constructor<?>[0];
}
return Arrays.stream(type.getDeclaredConstructors())
.filter(Constructors::isNonSynthetic)
.toArray(Constructor[]::new);
}
private static boolean isInnerClass(Class<?> type) {
try {
return type.getDeclaredField("this$0").isSynthetic();
}
catch (NoSuchFieldException ex) {
return false;
}
}
private static boolean isNonSynthetic(Constructor<?> constructor) {
return !constructor.isSynthetic();
}
private static MergedAnnotations[] getAnnotations(Constructor<?>[] candidates) {
MergedAnnotations[] candidateAnnotations = new MergedAnnotations[candidates.length];
for (int i = 0; i < candidates.length; i++) {
candidateAnnotations[i] = MergedAnnotations.from(candidates[i], SearchStrategy.SUPERCLASS);
}
return candidateAnnotations;
}
private static @Nullable Constructor<?> getConstructorBindingAnnotated(Class<?> type,
Constructor<?>[] candidates, MergedAnnotations[] mergedAnnotations) {
Constructor<?> result = null;
for (int i = 0; i < candidates.length; i++) {
if (mergedAnnotations[i].isPresent(ConstructorBinding.class)) {
Assert.state(candidates[i].getParameterCount() > 0,
() -> type.getName() + " declares @ConstructorBinding on a no-args constructor");
Assert.state(result == null,
() -> type.getName() + " has more than one @ConstructorBinding constructor");
result = candidates[i];
}
}
return result;
}
private static @Nullable Constructor<?> deduceBindConstructor(Class<?> type, Constructor<?>[] candidates) {
if (candidates.length == 1 && candidates[0].getParameterCount() > 0) {
if (type.isMemberClass() && Modifier.isPrivate(candidates[0].getModifiers())) {
return null;
}
return candidates[0];
}
Constructor<?> result = null;
for (Constructor<?> candidate : candidates) {
if (!Modifier.isPrivate(candidate.getModifiers())) {
if (result != null) {
return null;
}
result = candidate;
}
}
return (result != null && result.getParameterCount() > 0) ? result : null;
}
private static boolean isKotlinType(Class<?> type) {
return KotlinDetector.isKotlinPresent() && KotlinDetector.isKotlinType(type);
}
private static @Nullable Constructor<?> deduceKotlinBindConstructor(Class<?> type) {
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(type);
if (primaryConstructor != null && primaryConstructor.getParameterCount() > 0) {
return primaryConstructor;
}
return null;
}
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free