TypeElementMembers Class — spring-boot Architecture
Architecture documentation for the TypeElementMembers class in TypeElementMembers.java from the spring-boot codebase.
Entity Profile
Source Code
configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeElementMembers.java lines 45–241
class TypeElementMembers {
private static final String OBJECT_CLASS_NAME = Object.class.getName();
private static final String RECORD_CLASS_NAME = Record.class.getName();
private final MetadataGenerationEnvironment env;
private final TypeElement targetType;
private final boolean isRecord;
private final Map<String, VariableElement> fields = new LinkedHashMap<>();
private final Map<String, RecordComponentElement> recordComponents = new LinkedHashMap<>();
private final Map<String, List<ExecutableElement>> publicGetters = new LinkedHashMap<>();
private final Map<String, List<ExecutableElement>> publicSetters = new LinkedHashMap<>();
TypeElementMembers(MetadataGenerationEnvironment env, TypeElement targetType) {
this.env = env;
this.targetType = targetType;
this.isRecord = RECORD_CLASS_NAME.equals(targetType.getSuperclass().toString());
process(targetType);
}
private void process(TypeElement element) {
for (VariableElement field : ElementFilter.fieldsIn(element.getEnclosedElements())) {
processField(field);
}
for (RecordComponentElement recordComponent : ElementFilter.recordComponentsIn(element.getEnclosedElements())) {
processRecordComponent(recordComponent);
}
for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {
processMethod(method);
}
Element superType = this.env.getTypeUtils().asElement(element.getSuperclass());
if (superType instanceof TypeElement && !OBJECT_CLASS_NAME.equals(superType.toString())
&& !RECORD_CLASS_NAME.equals(superType.toString())) {
process((TypeElement) superType);
}
}
private void processMethod(ExecutableElement method) {
if (isPublic(method)) {
String name = method.getSimpleName().toString();
if (isGetter(method)) {
String propertyName = getAccessorName(name);
List<ExecutableElement> matchingGetters = this.publicGetters.computeIfAbsent(propertyName,
(k) -> new ArrayList<>());
TypeMirror returnType = method.getReturnType();
if (getMatchingGetter(matchingGetters, returnType) == null) {
matchingGetters.add(method);
}
}
else if (isSetter(method)) {
String propertyName = getAccessorName(name);
List<ExecutableElement> matchingSetters = this.publicSetters.computeIfAbsent(propertyName,
(k) -> new ArrayList<>());
TypeMirror paramType = method.getParameters().get(0).asType();
if (getMatchingSetter(matchingSetters, paramType) == null) {
matchingSetters.add(method);
}
}
}
}
private boolean isPublic(ExecutableElement method) {
Set<Modifier> modifiers = method.getModifiers();
return modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.ABSTRACT)
&& !modifiers.contains(Modifier.STATIC);
}
ExecutableElement getMatchingGetter(List<ExecutableElement> candidates, TypeMirror type) {
return getMatchingAccessor(candidates, type, ExecutableElement::getReturnType);
}
private ExecutableElement getMatchingSetter(List<ExecutableElement> candidates, TypeMirror type) {
return getMatchingAccessor(candidates, type, (candidate) -> candidate.getParameters().get(0).asType());
}
private ExecutableElement getMatchingAccessor(List<ExecutableElement> candidates, TypeMirror type,
Function<ExecutableElement, TypeMirror> typeExtractor) {
for (ExecutableElement candidate : candidates) {
TypeMirror candidateType = typeExtractor.apply(candidate);
if (this.env.getTypeUtils().isSameType(candidateType, type)) {
return candidate;
}
}
return null;
}
private boolean isGetter(ExecutableElement method) {
boolean hasParameters = !method.getParameters().isEmpty();
boolean returnsVoid = TypeKind.VOID == method.getReturnType().getKind();
if (hasParameters || returnsVoid) {
return false;
}
String name = method.getSimpleName().toString();
if (this.isRecord && this.fields.containsKey(name)) {
return true;
}
return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
}
private boolean isSetter(ExecutableElement method) {
if (this.isRecord) {
return false;
}
final String name = method.getSimpleName().toString();
return (name.startsWith("set") && name.length() > 3 && method.getParameters().size() == 1
&& isSetterReturnType(method));
}
private boolean isSetterReturnType(ExecutableElement method) {
TypeMirror returnType = method.getReturnType();
if (TypeKind.VOID == returnType.getKind()) {
return true;
}
if (TypeKind.DECLARED == returnType.getKind()
&& this.env.getTypeUtils().isSameType(method.getEnclosingElement().asType(), returnType)) {
return true;
}
if (TypeKind.TYPEVAR == returnType.getKind()) {
String resolvedType = this.env.getTypeUtils().getType(this.targetType, returnType);
return (resolvedType != null
&& resolvedType.equals(this.env.getTypeUtils().getQualifiedName(this.targetType)));
}
return false;
}
private String getAccessorName(String methodName) {
if (this.isRecord && this.fields.containsKey(methodName)) {
return methodName;
}
if (methodName.startsWith("is")) {
return lowerCaseFirstCharacter(methodName.substring(2));
}
if (methodName.startsWith("get") || methodName.startsWith("set")) {
return lowerCaseFirstCharacter(methodName.substring(3));
}
throw new IllegalStateException("methodName must start with 'is', 'get' or 'set', was '" + methodName + "'");
}
private String lowerCaseFirstCharacter(String string) {
return Character.toLowerCase(string.charAt(0)) + string.substring(1);
}
private void processField(VariableElement field) {
String name = field.getSimpleName().toString();
this.fields.putIfAbsent(name, field);
}
private void processRecordComponent(RecordComponentElement recordComponent) {
String name = recordComponent.getSimpleName().toString();
this.recordComponents.putIfAbsent(name, recordComponent);
}
Map<String, VariableElement> getFields() {
return Collections.unmodifiableMap(this.fields);
}
Map<String, RecordComponentElement> getRecordComponents() {
return Collections.unmodifiableMap(this.recordComponents);
}
Map<String, List<ExecutableElement>> getPublicGetters() {
return Collections.unmodifiableMap(this.publicGetters);
}
ExecutableElement getPublicGetter(String name, TypeMirror type) {
List<ExecutableElement> candidates = this.publicGetters.get(name);
return getPublicAccessor(candidates, type, (specificType) -> getMatchingGetter(candidates, specificType));
}
ExecutableElement getPublicSetter(String name, TypeMirror type) {
List<ExecutableElement> candidates = this.publicSetters.get(name);
return getPublicAccessor(candidates, type, (specificType) -> getMatchingSetter(candidates, specificType));
}
private ExecutableElement getPublicAccessor(List<ExecutableElement> candidates, TypeMirror type,
Function<TypeMirror, ExecutableElement> matchingAccessorExtractor) {
if (candidates != null) {
ExecutableElement matching = matchingAccessorExtractor.apply(type);
if (matching != null) {
return matching;
}
TypeMirror alternative = this.env.getTypeUtils().getWrapperOrPrimitiveFor(type);
if (alternative != null) {
return matchingAccessorExtractor.apply(alternative);
}
}
return null;
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free