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

net.zerobuilder.compiler.common.LessElements Maven / Gradle / Ivy

The newest version!
package net.zerobuilder.compiler.common;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor6;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;

import static javax.lang.model.element.ElementKind.PACKAGE;
import static javax.lang.model.util.ElementFilter.fieldsIn;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static net.zerobuilder.compiler.common.LessTypes.asTypeElement;

/**
 * Guava-free versions of some helpers from auto-common.
 */
public final class LessElements {

  private static final ElementVisitor TYPE_ELEMENT_VISITOR =
      new SimpleElementVisitor6() {
        @Override
        protected TypeElement defaultAction(Element e, Void p) {
          throw new IllegalArgumentException();
        }

        @Override
        public TypeElement visitType(TypeElement e, Void p) {
          return e;
        }
      };

  private static final ElementVisitor EXECUTABLE_ELEMENT_VISITOR =
      new SimpleElementVisitor6() {
        @Override
        protected ExecutableElement defaultAction(Element e, Void p) {
          throw new IllegalArgumentException();
        }

        @Override
        public ExecutableElement visitExecutable(ExecutableElement e, Void p) {
          return e;
        }
      };

  /**
   * Find all non-static, visible methods that match the predicate, and group by name.
   * In case of name conflict, the first found wins.
   * The iteration order is:
   * 
    *
  • {@code type} first, {@code Object} last
  • *
  • concrete types before interfaces
  • *
* Ideally the {@code predicate} should prevent name conflicts. * * @param type type to search * @param predicate filter * @return methods by name */ public static Map getLocalAndInheritedMethods( TypeElement type, Predicate predicate) { Map methods = new LinkedHashMap<>(); PackageElement pkg = getPackage(type); addFromSuperclass(pkg, type, methods, predicate); addFromInterfaces(pkg, type, methods, predicate); return methods; } public static Map getLocalAndInheritedFields( TypeElement type) { Map fields = new LinkedHashMap<>(); PackageElement pkg = getPackage(type); addFieldsFromSuperclass(pkg, type, fields); return fields; } private static void addFieldsFromSuperclass( PackageElement pkg, TypeElement type, Map methods) { addEnclosedFields(pkg, type, methods); TypeMirror superclass = type.getSuperclass(); if (superclass.getKind() == TypeKind.NONE) { return; } addFieldsFromSuperclass(pkg, asTypeElement(superclass), methods); } private static void addFromSuperclass( PackageElement pkg, TypeElement type, Map methods, Predicate predicate) { addEnclosedMethods(pkg, type, methods, predicate); TypeMirror superclass = type.getSuperclass(); if (superclass.getKind() == TypeKind.NONE) { return; } addFromSuperclass(pkg, asTypeElement(superclass), methods, predicate); } private static void addFromInterfaces( PackageElement pkg, TypeElement type, Map methods, Predicate predicate) { addEnclosedMethods(pkg, type, methods, predicate); for (TypeMirror superInterface : type.getInterfaces()) { addFromInterfaces(pkg, asTypeElement(superInterface), methods, predicate); } } private static void addEnclosedMethods(PackageElement pkg, TypeElement type, Map methods, Predicate predicate) { methodsIn(type.getEnclosedElements()) .stream() .filter(predicate) .forEach(method -> { if (method.getKind() == ElementKind.METHOD && !method.getModifiers().contains(Modifier.STATIC) && methodVisibleFromPackage(method, pkg)) { methods.computeIfAbsent(method.getSimpleName().toString(), name -> method); } }); } private static void addEnclosedFields(PackageElement pkg, TypeElement type, Map fields) { fieldsIn(type.getEnclosedElements()) .stream() .forEach(field -> { if (field.getKind() == ElementKind.FIELD && !field.getModifiers().contains(Modifier.STATIC) && methodVisibleFromPackage(field, pkg)) { fields.computeIfAbsent(field.getSimpleName().toString(), name -> field); } }); } private static boolean methodVisibleFromPackage(Element method, PackageElement pkg) { Visibility visibility = Visibility.ofElement(method); switch (visibility) { case PRIVATE: return false; case DEFAULT: return getPackage(method).equals(pkg); default: return true; } } private static PackageElement getPackage(Element element) { while (element.getKind() != PACKAGE) { element = element.getEnclosingElement(); } return (PackageElement) element; } public static ExecutableElement asExecutable(Element element) { return element.accept(EXECUTABLE_ELEMENT_VISITOR, null); } static TypeElement asType(Element element) { return element.accept(TYPE_ELEMENT_VISITOR, null); } private LessElements() { throw new UnsupportedOperationException("no instances"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy