com.slimgears.apt.util.ElementUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apt-utils Show documentation
Show all versions of apt-utils Show documentation
General purpose utils / module: apt-utils
package com.slimgears.apt.util;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.base.Preconditions;
import com.slimgears.apt.data.Environment;
import com.slimgears.apt.data.TypeInfo;
import com.slimgears.util.stream.Optionals;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.slimgears.util.stream.Streams.ofType;
import static com.slimgears.util.stream.Streams.self;
@SuppressWarnings({"WeakerAccess", "UnstableApiUsage"})
public class ElementUtils {
public static boolean isKnownType(TypeElement typeElement) {
return Environment.instance().isIgnoredType(TypeInfo.of(typeElement));
}
public static boolean isUnknownType(TypeElement typeElement) {
return !isKnownType(typeElement);
}
public static boolean isPublic(Element element) {
return modifiersContainAll(element, Modifier.PUBLIC);
}
public static boolean isNotStatic(Element element) {
return modifiersContainNone(element, Modifier.STATIC);
}
public static boolean isAbstract(Element element) {
return modifiersContainNone(element, Modifier.DEFAULT) && modifiersContainAll(element, Modifier.ABSTRACT);
}
public static boolean isInterface(Element element) {
return isOfKind(element, ElementKind.INTERFACE);
}
public static boolean isOfKind(Element element, ElementKind kind) {
return element.getKind() == kind;
}
public static boolean modifiersContainAll(Element element, Modifier... modifiers) {
Set elementModifiers = element.getModifiers();
return elementModifiers.containsAll(Arrays.asList(modifiers));
}
public static boolean modifiersContainNone(Element element, Modifier... modifiers) {
Set elementModifiers = element.getModifiers();
return Stream.of(modifiers).noneMatch(elementModifiers::contains);
}
public static String fullName(Element element) {
return Optional
.ofNullable(element.getEnclosingElement())
.map(e -> fullName(e) + "." + element.getSimpleName().toString())
.orElseGet(element::toString);
}
public static Predicate super Element> ofKind(ElementKind kind) {
return el -> el.getKind() == kind;
}
public static boolean isEnum(TypeElement typeElement) {
return ofKind(ElementKind.ENUM).test(typeElement);
}
public static boolean isEnumConstant(Element element) {
return ofKind(ElementKind.ENUM_CONSTANT).test(element);
}
public static boolean hasAnnotation(Element elemenet, Class extends Annotation> annotationCls) {
return MoreElements.isAnnotationPresent(elemenet, annotationCls);
}
public static boolean hasErrors(TypeMirror typeMirror) {
return typeMirror.getKind() == TypeKind.ERROR || (typeMirror.getKind() == TypeKind.DECLARED && MoreTypes
.asDeclared(typeMirror)
.getTypeArguments()
.stream()
.anyMatch(ElementUtils::hasErrors));
}
public static Stream findErrors(TypeMirror typeMirror) {
Stream thisError = typeMirror.getKind() == TypeKind.ERROR
? Stream.of(typeMirror)
: Stream.empty();
return typeMirror.getKind() == TypeKind.DECLARED
? Stream.concat(
thisError,
MoreTypes
.asDeclared(typeMirror)
.getTypeArguments()
.stream()
.flatMap(ElementUtils::findErrors))
: thisError;
}
public static boolean hasInterface(TypeMirror type, Class... interfaceTypes) {
if (type.getKind() != TypeKind.DECLARED) {
return false;
}
if (hasExtendsBound(type, interfaceTypes)) {
return true;
}
Set actualInterfaces = Optional.of(type)
.flatMap(Optionals.ofType(DeclaredType.class))
.map(ElementUtils::getHierarchy)
.orElseGet(Stream::empty)
.collect(Collectors.toSet());
return Arrays
.stream(interfaceTypes)
.allMatch(it -> actualInterfaces.stream().anyMatch(t -> MoreTypes.isTypeOf(it, t)));
}
private static boolean hasExtendsBound(TypeMirror type, Class... interfaceTypes) {
if (type.getKind() == TypeKind.WILDCARD) {
return boundHasInterface(((WildcardType)type).getExtendsBound(), interfaceTypes);
} else if (type.getKind() == TypeKind.TYPEVAR) {
return boundHasInterface(((TypeVariable)type).getUpperBound(), interfaceTypes);
}
return false;
}
private static boolean boundHasInterface(TypeMirror bound, Class... interfaceTypes) {
if (bound.getKind() == TypeKind.DECLARED) {
return hasInterface(bound, interfaceTypes);
}
if (bound.getKind() == TypeKind.WILDCARD || bound.getKind() == TypeKind.TYPEVAR) {
return hasExtendsBound(bound, interfaceTypes);
}
if (bound.getKind() == TypeKind.INTERSECTION) {
return ((IntersectionType)bound).getBounds()
.stream()
.flatMap(ofType(DeclaredType.class))
.flatMap(ElementUtils::getHierarchy)
.collect(Collectors.toSet())
.containsAll(Arrays.asList(interfaceTypes));
}
return false;
}
public static Stream getMethodAnnotation(ExecutableElement element, Class cls) {
return getOverrides(element).map(ee -> ee.getAnnotation(cls)).filter(Objects::nonNull);
}
public static Stream getMethodAnnotations(ExecutableElement element) {
return getOverrides(element).flatMap(ee -> ee.getAnnotationMirrors().stream());
}
public static Stream getOverrides(ExecutableElement element) {
TypeElement overridenType = MoreElements.asType(element.getEnclosingElement());
return Stream.concat(Stream.of(element), getOverrides(overridenType, element));
}
private static Stream getOverrides(TypeElement overridenType, ExecutableElement element) {
return Stream
.concat(
Stream.of(overridenType.getSuperclass()).flatMap(ElementUtils::toTypeElement),
overridenType.getInterfaces().stream().flatMap(ElementUtils::toTypeElement))
.flatMap(superType -> Stream
.concat(Stream.of(superType)
.map(TypeElement::getEnclosedElements)
.flatMap(Collection::stream)
.flatMap(ofType(ExecutableElement.class))
.filter(ee -> overrides(element, ee)),
getOverrides(superType, element)));
}
public static boolean overrides(ExecutableElement overrider, ExecutableElement overriden) {
return Environment.instance().elements().overrides(overrider, overriden, MoreElements.asType(overrider.getEnclosingElement()));
}
public static Stream getReferencedTypes(TypeElement typeElement) {
Stream enclosedElements = typeElement
.getEnclosedElements()
.stream()
.filter(ElementUtils::isPublic)
.filter(ElementUtils::isNotStatic)
.flatMap(element -> Stream.concat(
Stream.of(element)
.flatMap(ofType(ExecutableElement.class))
.flatMap(ElementUtils::getReferencedTypes),
Stream.of(element)
.flatMap(ofType(VariableElement.class))
.flatMap(v -> getReferencedTypeParams(v.asType()))
.flatMap(ElementUtils::toTypeElement)))
.filter(ElementUtils::isUnknownType)
.distinct();
return Stream.concat(getHierarchy(typeElement), enclosedElements);
}
public static Stream getReferencedTypes(ExecutableElement executableElement) {
return Stream.concat(
Stream.of(executableElement.getReturnType()),
executableElement.getParameters().stream()
.map(VariableElement::asType))
.flatMap(ElementUtils::getReferencedTypeParams)
.flatMap(ElementUtils::toTypeElement)
.distinct();
}
public static Stream getReferencedTypeParams(TypeMirror type) {
return Stream.of(
Stream.of(type)
.flatMap(ofType(DeclaredType.class)),
Stream.of(type)
.flatMap(ofType(WildcardType.class))
.flatMap(wt -> Stream.of(wt.getExtendsBound(), wt.getSuperBound()))
.flatMap(ofType(DeclaredType.class))
.flatMap(t -> t.getTypeArguments().stream())
.flatMap(ElementUtils::getReferencedTypeParams),
Stream.of(type)
.flatMap(ofType(DeclaredType.class))
.flatMap(t -> t.getTypeArguments().stream())
.flatMap(ElementUtils::getReferencedTypeParams),
Stream.of(type)
.flatMap(ofType(ArrayType.class))
.map(ArrayType::getComponentType))
.flatMap(self())
.filter(DeclaredType.class::isInstance)
.map(typeMirror -> (TypeMirror)typeMirror)
.distinct();
}
public static Stream getHierarchy(DeclaredType declaredType) {
return Stream.of(
Stream.of(declaredType),
getSuperClass(declaredType).flatMap(ElementUtils::getHierarchy),
getInterfaces(declaredType).flatMap(ElementUtils::getHierarchy))
.flatMap(self())
.distinct();
}
public static Stream getMethods(DeclaredType declaredType) {
return toTypeElement(declaredType)
.map(TypeElement::getEnclosedElements)
.flatMap(Collection::stream)
.flatMap(ofType(ExecutableElement.class))
.filter(ElementUtils::isPublic)
.filter(ElementUtils::isNotStatic);
}
public static Stream getHierarchy(TypeElement typeElement) {
return Stream.of(
Stream.of(typeElement),
Stream.of(typeElement)
.map(TypeElement::getSuperclass)
.flatMap(ElementUtils::toTypeElement)
.flatMap(ElementUtils::getHierarchy),
Stream.of(typeElement)
.flatMap(t -> t.getInterfaces().stream())
.flatMap(ElementUtils::toTypeElement)
.flatMap(ElementUtils::getHierarchy))
.flatMap(self())
.distinct();
}
public static Stream toDeclaredTypeStream(TypeElement typeElement) {
return Stream.of(typeElement)
.map(TypeElement::asType)
.flatMap(ofType(DeclaredType.class));
}
public static DeclaredType toDeclaredType(TypeElement typeElement) {
return toDeclaredTypeStream(typeElement)
.findFirst()
.orElseThrow(() -> new RuntimeException("Cannot convert " + typeElement.getQualifiedName() + " to DeclaredType"));
}
public static Stream toTypeElement(TypeMirror type) {
return Stream.of(type)
.flatMap(ofType(DeclaredType.class))
.map(DeclaredType::asElement)
.flatMap(ofType(TypeElement.class));
}
public static TypeInfo[] typesFromAnnotation(A annotation, Function classRetriever) {
return Stream
.of(typeMirrorsFromAnnotation(annotation, classRetriever))
.map(TypeInfo::of)
.toArray(TypeInfo[]::new);
}
public static TypeMirror[] typeMirrorsFromAnnotation(A annotation, Function classRetriever) {
try {
return Stream
.of(classRetriever.apply(annotation))
.map(TypeMirror.class::cast)
.toArray(TypeMirror[]::new);
} catch (MirroredTypesException e) {
return e.getTypeMirrors().toArray(new TypeMirror[0]);
}
}
public static TypeInfo typeFromAnnotation(A annotation, Function classRetriever) {
return TypeInfo.of(Preconditions.checkNotNull(typeMirrorFromAnnotation(annotation, classRetriever)));
}
public static TypeMirror findInterface(TypeMirror typeMirror, Class interfaceType) {
Optional type = Optional.ofNullable(typeMirror);
return Stream.of(
type.flatMap(Optionals.ofType(IntersectionType.class))
.map(it -> it.getBounds().stream())
.orElseGet(Stream::empty),
type
.flatMap(Optionals.ofType(TypeVariable.class))
.map(TypeVariable::getUpperBound)
.map(t -> findInterface(t, interfaceType))
.map(Stream::of)
.orElseGet(Stream::empty),
type
.flatMap(Optionals.ofType(WildcardType.class))
.map(WildcardType::getExtendsBound)
.map(t -> findInterface(t, interfaceType))
.map(Stream::of)
.orElseGet(Stream::empty),
type
.flatMap(Optionals.ofType(DeclaredType.class))
.map(ElementUtils::getHierarchy)
.orElseGet(Stream::empty))
.flatMap(Function.identity())
.map(t -> (TypeMirror)t)
.filter(t -> MoreTypes.isTypeOf(interfaceType, t))
.findFirst()
.orElse(null);
}
public static TypeMirror typeMirrorFromAnnotation(A annotation, Function classRetriever) {
try {
classRetriever.apply(annotation);
return null;
} catch (MirroredTypeException e) {
return e.getTypeMirror();
}
}
private static Stream getSuperClass(DeclaredType type) {
return toTypeElement(type)
.map(TypeElement::getSuperclass)
.flatMap(ofType(DeclaredType.class));
}
private static Stream getInterfaces(DeclaredType type) {
return toTypeElement(type)
.flatMap(e -> e.getInterfaces().stream())
.flatMap(ofType(DeclaredType.class));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy