All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dynodao.processor.context.Processors Maven / Gradle / Ivy

package com.github.dynodao.processor.context;

import lombok.experimental.Delegate;

import javax.inject.Inject;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;

/**
 * Provides access to {@link Elements} and {@link Types} utility classes, as well as providing some additional
 * utility methods related to them.
 */
public class Processors implements Elements, Types {

    @Delegate(types = Elements.class)
    private final Elements elementUtils;

    @Delegate(types = Types.class)
    private final Types typeUtils;

    @Inject Processors(ProcessorContext processorContext) {
        this.elementUtils = processorContext.getProcessingEnvironment().getElementUtils();
        this.typeUtils = processorContext.getProcessingEnvironment().getTypeUtils();
    }

    /**
     * Returns the {@link TypeElement} corresponding to the {@link Class} provided.
     * @param clazz the class to get the type of
     * @return the {@link TypeElement}
     * @see Elements#getTypeElement(CharSequence)
     */
    public TypeElement getTypeElement(Class clazz) {
        return getTypeElement(clazz.getCanonicalName());
    }

    /**
     * Returns the {@link DeclaredType} of the type with the given typeArguments.
     * @param type the class type
     * @param typeArguments the template arguments, if any
     * @return the {@link DeclaredType}
     * @see Types#getDeclaredType(TypeElement, TypeMirror...)
     */
    public DeclaredType getDeclaredType(Class type, Class... typeArguments) {
        TypeElement typeElement = getTypeElement(type.getCanonicalName());
        TypeMirror[] args = Arrays.stream(typeArguments)
                .map(clazz -> getTypeElement(clazz.getCanonicalName()).asType())
                .toArray(TypeMirror[]::new);
        return getDeclaredType(typeElement, args);
    }

    /**
     * Returns true if the typeMirror is the same type as the declared type
     * constructed by the Class arguments.
     * @param typeMirror the type to test
     * @param type the declared class type
     * @param typeArguments the template arguments of the declared class type, if any
     * @return true if typeMirror is the same declared type as the classes provided
     * @see Types#isSameType(TypeMirror, TypeMirror)
     * @see #getDeclaredType(Class, Class[])
     */
    public boolean isSameType(TypeMirror typeMirror, Class type, Class... typeArguments) {
        return isSameType(typeMirror, getDeclaredType(type, typeArguments));
    }

    /**
     * Returns the method element enclosed in the typeElement whose simple name is methodName.
     * @param typeElement the type to find a method in
     * @param methodName the method name to find
     * @return the method
     * @throws IllegalArgumentException if the method does not exist
     */
    public ExecutableElement getMethodByName(TypeElement typeElement, String methodName) {
        return typeElement.getEnclosedElements().stream()
                .filter(element -> element.getKind().equals(ElementKind.METHOD))
                .filter(method -> method.getSimpleName().contentEquals(methodName))
                .map(method -> (ExecutableElement) method)
                .findFirst().orElseThrow(() -> new IllegalArgumentException(String.format("no such method [%s] in [%s]", methodName, typeElement)));
    }

    /**
     * Returns the supertype of typeMirror whose erasure is the same type as the erasure of supertype.
     * @param typeMirror the type to find a supertype of
     * @param supertype the supertype to find
     * @return the supertype of typeMirror whose erasure is the same as supertype
     * @throws IllegalArgumentException if no supertype matches supertype
     */
    public TypeMirror getSupertypeWithErasureSameAs(TypeMirror typeMirror, TypeMirror supertype) {
        TypeMirror erasure = erasure(supertype);
        Queue queue = new ArrayDeque<>();
        queue.add(typeMirror);
        while (!queue.isEmpty()) {
            TypeMirror type = queue.poll();
            queue.addAll(directSupertypes(type));

            if (isSameType(erasure, erasure(type))) {
                return type;
            }
        }
        throw new IllegalArgumentException(String.format("%s has no supertype with erasure the same as %s", typeMirror, supertype));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy