org.dominokit.domino.apt.commons.ProcessorUtil Maven / Gradle / Ivy
package org.dominokit.domino.apt.commons;
import com.squareup.javapoet.TypeName;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
public class ProcessorUtil {
private static final int FIRST_ARGUMENT = 0;
private static final int SECOND_ARGUMENT = 1;
protected final Messager messager;
protected final Filer filer;
protected final Types types;
protected final Elements elements;
protected final ProcessingEnvironment processingEnv;
public ProcessorUtil(ProcessingEnvironment processingEnv) {
this.messager = processingEnv.getMessager();
this.filer = processingEnv.getFiler();
this.types = processingEnv.getTypeUtils();
this.elements = processingEnv.getElementUtils();
this.processingEnv = processingEnv;
}
public Messager getMessager() {
return messager;
}
public Types getTypes() {
return types;
}
public Elements getElements() {
return elements;
}
public List getAnnotatedMethods(TypeMirror beanType, Class annotation) {
return getAnnotatedElements(beanType, annotation, element -> ElementKind.METHOD.equals(element.getKind()));
}
public List getAnnotatedFields(TypeMirror beanType, Class annotation) {
return getAnnotatedElements(beanType, annotation, element -> ElementKind.FIELD.equals(element.getKind()));
}
public List getAnnotatedElements(TypeMirror beanType, Class annotation, Function filter) {
TypeElement typeElement = (TypeElement) types.asElement(beanType);
final List methods = new ArrayList<>();
List annotatedMethods = getAnnotatedElements(typeElement, annotation, filter);
methods.addAll(annotatedMethods);
return methods;
}
public List getAnnotatedElements(TypeElement typeElement, Class annotation, Function filter) {
TypeMirror superclass = typeElement.getSuperclass();
if (superclass.getKind().equals(TypeKind.NONE)) {
return new ArrayList<>();
}
List methods = typeElement.getEnclosedElements()
.stream()
.filter(filter::apply)
.filter(element -> nonNull(element.getAnnotation(annotation)))
.collect(Collectors.toList());
methods.addAll(getAnnotatedElements((TypeElement) types.asElement(superclass), annotation, filter));
return methods;
}
public Optional findTypeArgument(TypeMirror element, Class targetClass) {
if (element.getKind().equals(TypeKind.NONE)) {
return Optional.empty();
}
DeclaredType elementType = (DeclaredType) element;
List typeArguments = elementType.getTypeArguments();
for (TypeMirror type : typeArguments) {
if (isAssignableFrom(type, targetClass)) {
return Optional.of(type);
}
}
TypeElement typeElement = (TypeElement) types.asElement(element);
List interfaces = typeElement.getInterfaces();
for (TypeMirror interfaceType : interfaces) {
List interfaceTypeArguments = ((DeclaredType) interfaceType).getTypeArguments();
for (TypeMirror type : interfaceTypeArguments) {
if (isAssignableFrom(type, targetClass)) {
return Optional.of(type);
}
}
}
return findTypeArgument(typeElement.getSuperclass(), targetClass);
}
public String capitalizeFirstLetter(String input) {
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
public String smallFirstLetter(String input) {
return input.substring(0, 1).toLowerCase() + input.substring(1);
}
public String lowerFirstLetter(String input) {
return input.substring(0, 1).toLowerCase() + input.substring(1);
}
public boolean isAssignableFrom(Element element, Class targetClass) {
return types.isAssignable(element.asType(), types.getDeclaredType(elements.getTypeElement(targetClass.getCanonicalName())));
}
public boolean isAssignableFrom(TypeMirror element, Class targetClass) {
return types.isAssignable(element, types.getDeclaredType(elements.getTypeElement(targetClass.getCanonicalName())));
}
public A findClassAnnotation(Element classElement, Class annotation){
A result = classElement.getAnnotation(annotation);
if(nonNull(result)){
return result;
}
TypeMirror superclass = ((TypeElement) classElement).getSuperclass();
if (superclass.getKind().equals(TypeKind.NONE)) {
return null;
} else {
return findClassAnnotation(types.asElement(superclass), annotation);
}
}
public Optional findClassValueFromClassAnnotation(Element classElement, Class annotation, String paramName){
Optional result = getClassValueFromAnnotation(classElement, annotation, paramName);
if(result.isPresent()){
return result;
}
TypeMirror superclass = ((TypeElement) classElement).getSuperclass();
if (superclass.getKind().equals(TypeKind.NONE)) {
return Optional.empty();
} else {
return findClassValueFromClassAnnotation(types.asElement(superclass), annotation,paramName);
}
}
public Optional getClassValueFromAnnotation(Element element, Class annotation, String paramName) {
for (AnnotationMirror am : element.getAnnotationMirrors()) {
if (types.isSameType(am.getAnnotationType(), elements.getTypeElement(annotation.getCanonicalName()).asType())) {
for (Map.Entry entry : am.getElementValues().entrySet()) {
if (paramName.equals(entry.getKey().getSimpleName().toString())) {
AnnotationValue annotationValue = entry.getValue();
return Optional.of((DeclaredType) annotationValue.getValue());
}
}
}
}
return Optional.empty();
}
public List getClassArrayValueFromAnnotation(Element element, Class annotation, String paramName) {
List values = new ArrayList<>();
for (AnnotationMirror am : element.getAnnotationMirrors()) {
if (types.isSameType(am.getAnnotationType(), elements.getTypeElement(annotation.getCanonicalName()).asType())) {
for (Map.Entry entry : am.getElementValues().entrySet()) {
if (paramName.equals(entry.getKey().getSimpleName().toString())) {
List classesTypes = (List) entry.getValue().getValue();
Iterator iterator = classesTypes.iterator();
while (iterator.hasNext()) {
AnnotationValue next = iterator.next();
values.add((TypeMirror) next.getValue());
}
}
}
}
}
return values;
}
public List getElementMethods(Element element) {
return element.getEnclosedElements()
.stream()
.filter(e -> e.getKind() == ElementKind.METHOD)
.map(e -> (ExecutableElement) e)
.collect(Collectors.toList());
}
public boolean isStringType(TypeMirror typeMirror) {
TypeMirror stringType = elements.getTypeElement("java.lang.String").asType();
return types.isAssignable(stringType, typeMirror);
}
/**
* wrapperType.
*
* @param type a {@link TypeMirror} object.
* @return a {@link TypeName} object.
*/
public TypeName wrapperType(TypeMirror type) {
if (isPrimitive(type)) {
if ("boolean".equals(type.toString())) {
return TypeName.get(Boolean.class);
} else if ("byte".equals(type.toString())) {
return TypeName.get(Byte.class);
} else if ("short".equals(type.toString())) {
return TypeName.get(Short.class);
} else if ("int".equals(type.toString())) {
return TypeName.get(Integer.class);
} else if ("long".equals(type.toString())) {
return TypeName.get(Long.class);
} else if ("char".equals(type.toString())) {
return TypeName.get(Character.class);
} else if ("float".equals(type.toString())) {
return TypeName.get(Float.class);
} else if ("double".equals(type.toString())) {
return TypeName.get(Double.class);
} else {
return TypeName.get(Void.class);
}
} else {
return TypeName.get(type);
}
}
public boolean isPrimitive(TypeMirror typeMirror) {
return typeMirror.getKind().isPrimitive();
}
/**
* isPrimitiveArray.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isPrimitiveArray(TypeMirror typeMirror) {
return (isArray(typeMirror) && isPrimitive(arrayComponentType(typeMirror))) || isPrimitive2dArray(typeMirror);
}
private boolean isPrimitive2dArray(TypeMirror typeMirror) {
return is2dArray(typeMirror) && isPrimitiveArray(arrayComponentType(typeMirror));
}
/**
* isArray.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isArray(TypeMirror typeMirror) {
return TypeKind.ARRAY.compareTo(typeMirror.getKind()) == 0;
}
/**
* is2dArray.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean is2dArray(TypeMirror typeMirror) {
return isArray(typeMirror) && isArray(arrayComponentType(typeMirror));
}
/**
* arrayComponentType.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link TypeMirror} object.
*/
public TypeMirror arrayComponentType(TypeMirror typeMirror) {
return ((ArrayType) typeMirror).getComponentType();
}
/**
* deepArrayComponentType.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link TypeMirror} object.
*/
public TypeMirror deepArrayComponentType(TypeMirror typeMirror) {
TypeMirror type = ((ArrayType) typeMirror).getComponentType();
return isArray(type) ? arrayComponentType(type) : type;
}
/**
* isEnum.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isEnum(TypeMirror typeMirror) {
return !isNull(types.asElement(typeMirror))
&& !isPrimitive(typeMirror)
&& !isPrimitiveArray(typeMirror)
&& ElementKind.ENUM.compareTo(types.asElement(typeMirror).getKind()) == 0;
}
/**
* isCollection.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isCollection(TypeMirror typeMirror) {
return !isPrimitive(typeMirror) && isAssignableFrom(typeMirror, Collection.class);
}
/**
* isIterable.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isIterable(TypeMirror typeMirror) {
return !isPrimitive(typeMirror) && isAssignableFrom(typeMirror, Iterable.class);
}
/**
* isMap.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a boolean.
*/
public boolean isMap(TypeMirror typeMirror) {
return !isPrimitive(typeMirror) && isAssignableFrom(typeMirror, Map.class);
}
/**
* firstTypeArgument.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link TypeMirror} object.
*/
public TypeMirror firstTypeArgument(TypeMirror typeMirror) {
return ((DeclaredType) typeMirror).getTypeArguments().get(FIRST_ARGUMENT);
}
/**
* secondTypeArgument.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link TypeMirror} object.
*/
public TypeMirror secondTypeArgument(TypeMirror typeMirror) {
return ((DeclaredType) typeMirror).getTypeArguments().get(SECOND_ARGUMENT);
}
/**
* getPackage.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link String} object.
*/
public String getPackage(TypeMirror typeMirror) {
return elements.getPackageOf(types.asElement(typeMirror)).getSimpleName().toString();
}
/**
* simpleName.
*
* @param typeMirror a {@link TypeMirror} object.
* @return a {@link Name} object.
*/
public Name simpleName(TypeMirror typeMirror) {
return types.asElement(typeMirror).getSimpleName();
}
}