use of io.micronaut.annotation.processing.PublicMethodVisitor in project micronaut-core by micronaut-projects.
the class JavaClassElement method getBeanProperties.
@Override
public List<PropertyElement> getBeanProperties() {
if (this.beanProperties == null) {
Map<String, BeanPropertyData> props = new LinkedHashMap<>();
Map<String, VariableElement> fields = new LinkedHashMap<>();
if (isRecord()) {
classElement.asType().accept(new SuperclassAwareTypeVisitor<Object, Object>(visitorContext) {
@Override
protected boolean isAcceptable(Element element) {
return JavaModelUtils.isRecord(element);
}
@Override
public Object visitDeclared(DeclaredType type, Object o) {
Element element = type.asElement();
if (isAcceptable(element)) {
List<? extends Element> enclosedElements = element.getEnclosedElements();
for (Element enclosedElement : enclosedElements) {
if (JavaModelUtils.isRecordComponent(enclosedElement) || enclosedElement instanceof ExecutableElement) {
if (enclosedElement.getKind() != ElementKind.CONSTRUCTOR) {
accept(type, enclosedElement, o);
}
}
}
}
return o;
}
@Override
protected void accept(DeclaredType type, Element element, Object o) {
String name = element.getSimpleName().toString();
if (element instanceof ExecutableElement) {
BeanPropertyData beanPropertyData = props.get(name);
if (beanPropertyData != null) {
beanPropertyData.getter = (ExecutableElement) element;
}
} else {
props.computeIfAbsent(name, propertyName -> {
BeanPropertyData beanPropertyData = new BeanPropertyData(propertyName);
beanPropertyData.declaringType = JavaClassElement.this;
beanPropertyData.type = mirrorToClassElement(element.asType(), visitorContext, genericTypeInfo, true);
return beanPropertyData;
});
}
}
}, null);
} else {
classElement.asType().accept(new PublicMethodVisitor<Object, Object>(visitorContext) {
final String[] readPrefixes = getValue(AccessorsStyle.class, "readPrefixes", String[].class).orElse(new String[] { AccessorsStyle.DEFAULT_READ_PREFIX });
final String[] writePrefixes = getValue(AccessorsStyle.class, "writePrefixes", String[].class).orElse(new String[] { AccessorsStyle.DEFAULT_WRITE_PREFIX });
@Override
protected boolean isAcceptable(javax.lang.model.element.Element element) {
if (element.getKind() == ElementKind.FIELD) {
return true;
}
if (element.getKind() == ElementKind.METHOD && element instanceof ExecutableElement) {
Set<Modifier> modifiers = element.getModifiers();
if (modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.STATIC)) {
ExecutableElement executableElement = (ExecutableElement) element;
String methodName = executableElement.getSimpleName().toString();
if (methodName.contains("$")) {
return false;
}
if (NameUtils.isReaderName(methodName, readPrefixes) && executableElement.getParameters().isEmpty()) {
return true;
} else {
return NameUtils.isWriterName(methodName, writePrefixes) && executableElement.getParameters().size() == 1;
}
}
}
return false;
}
@Override
protected void accept(DeclaredType declaringType, javax.lang.model.element.Element element, Object o) {
if (element instanceof VariableElement) {
fields.put(element.getSimpleName().toString(), (VariableElement) element);
return;
}
ExecutableElement executableElement = (ExecutableElement) element;
String methodName = executableElement.getSimpleName().toString();
final TypeElement declaringTypeElement = (TypeElement) executableElement.getEnclosingElement();
if (NameUtils.isReaderName(methodName, readPrefixes) && executableElement.getParameters().isEmpty()) {
String propertyName = NameUtils.getPropertyNameForGetter(methodName, readPrefixes);
TypeMirror returnType = executableElement.getReturnType();
ClassElement getterReturnType;
if (returnType instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) returnType;
final String tvn = tv.toString();
final ClassElement classElement = getTypeArguments().get(tvn);
if (classElement != null) {
getterReturnType = classElement;
} else {
getterReturnType = mirrorToClassElement(returnType, visitorContext, JavaClassElement.this.genericTypeInfo, true);
}
} else {
getterReturnType = mirrorToClassElement(returnType, visitorContext, JavaClassElement.this.genericTypeInfo, true);
}
BeanPropertyData beanPropertyData = props.computeIfAbsent(propertyName, BeanPropertyData::new);
configureDeclaringType(declaringTypeElement, beanPropertyData);
beanPropertyData.type = getterReturnType;
beanPropertyData.getter = executableElement;
if (beanPropertyData.setter != null) {
TypeMirror typeMirror = beanPropertyData.setter.getParameters().get(0).asType();
ClassElement setterParameterType = mirrorToClassElement(typeMirror, visitorContext, JavaClassElement.this.genericTypeInfo, true);
if (!setterParameterType.isAssignable(getterReturnType)) {
// not a compatible setter
beanPropertyData.setter = null;
}
}
} else if (NameUtils.isWriterName(methodName, writePrefixes) && executableElement.getParameters().size() == 1) {
String propertyName = NameUtils.getPropertyNameForSetter(methodName, writePrefixes);
TypeMirror typeMirror = executableElement.getParameters().get(0).asType();
ClassElement setterParameterType = mirrorToClassElement(typeMirror, visitorContext, JavaClassElement.this.genericTypeInfo, true);
BeanPropertyData beanPropertyData = props.computeIfAbsent(propertyName, BeanPropertyData::new);
configureDeclaringType(declaringTypeElement, beanPropertyData);
ClassElement propertyType = beanPropertyData.type;
if (propertyType != null) {
if (propertyType.getName().equals(setterParameterType.getName())) {
beanPropertyData.setter = executableElement;
}
} else {
beanPropertyData.setter = executableElement;
}
}
}
private void configureDeclaringType(TypeElement declaringTypeElement, BeanPropertyData beanPropertyData) {
if (beanPropertyData.declaringType == null && !classElement.equals(declaringTypeElement)) {
beanPropertyData.declaringType = mirrorToClassElement(declaringTypeElement.asType(), visitorContext, genericTypeInfo, true);
} else if (beanPropertyData.declaringType == null) {
beanPropertyData.declaringType = mirrorToClassElement(declaringTypeElement.asType(), visitorContext, genericTypeInfo, false);
}
}
}, null);
}
if (!props.isEmpty()) {
this.beanProperties = new ArrayList<>(props.size());
for (Map.Entry<String, BeanPropertyData> entry : props.entrySet()) {
String propertyName = entry.getKey();
BeanPropertyData value = entry.getValue();
final VariableElement fieldElement = fields.get(propertyName);
if (value.getter != null) {
final AnnotationMetadata annotationMetadata;
List<Element> parents = new ArrayList<>();
if (fieldElement != null) {
parents.add(fieldElement);
}
if (value.setter != null) {
parents.add(value.setter);
}
if (!parents.isEmpty()) {
annotationMetadata = visitorContext.getAnnotationUtils().getAnnotationMetadata(parents, value.getter);
} else {
annotationMetadata = visitorContext.getAnnotationUtils().newAnnotationBuilder().buildForMethod(value.getter);
}
JavaPropertyElement propertyElement = new JavaPropertyElement(value.declaringType == null ? this : value.declaringType, value.getter, annotationMetadata, propertyName, value.type, value.setter == null, visitorContext) {
@Override
public ClassElement getGenericType() {
TypeMirror propertyType = value.getter.getReturnType();
if (fieldElement != null) {
TypeMirror fieldType = fieldElement.asType();
if (visitorContext.getTypes().isAssignable(fieldType, propertyType)) {
propertyType = fieldType;
}
}
Map<String, Map<String, TypeMirror>> declaredGenericInfo = getGenericTypeInfo();
return parameterizedClassElement(propertyType, visitorContext, declaredGenericInfo);
}
@Override
public Optional<String> getDocumentation() {
Elements elements = visitorContext.getElements();
String docComment = elements.getDocComment(value.getter);
return Optional.ofNullable(docComment);
}
@Override
public Optional<MethodElement> getWriteMethod() {
if (value.setter != null) {
return Optional.of(new JavaMethodElement(JavaClassElement.this, value.setter, visitorContext.getAnnotationUtils().newAnnotationBuilder().buildForMethod(value.setter), visitorContext));
}
return Optional.empty();
}
@Override
public Optional<MethodElement> getReadMethod() {
return Optional.of(new JavaMethodElement(JavaClassElement.this, value.getter, annotationMetadata, visitorContext));
}
};
beanProperties.add(propertyElement);
}
}
this.beanProperties = Collections.unmodifiableList(beanProperties);
} else {
this.beanProperties = Collections.emptyList();
}
}
return Collections.unmodifiableList(beanProperties);
}
Aggregations