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

io.dinject.generator.BeanReader Maven / Gradle / Ivy

There is a newer version: 2.3
Show newest version
package io.dinject.generator;

import io.dinject.Bean;
import io.dinject.Factory;

import javax.annotation.Generated;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
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.TypeElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

class BeanReader {

  /**
   * Annotations that we don't bother registering lists for.
   */
  private static Set EXCLUDED_ANNOTATIONS = new HashSet<>();

  static {
    EXCLUDED_ANNOTATIONS.add(Singleton.class.getName());
    EXCLUDED_ANNOTATIONS.add(Named.class.getName());
    EXCLUDED_ANNOTATIONS.add(Factory.class.getName());
    EXCLUDED_ANNOTATIONS.add(Generated.class.getName());
    EXCLUDED_ANNOTATIONS.add(Constants.KOTLIN_METADATA);
    EXCLUDED_ANNOTATIONS.add(Constants.PATH);
  }

  private final TypeElement beanType;

  private final ProcessingContext processingContext;

  private final String shortName;

  private String name;

  private MethodReader injectConstructor;

  private final List otherConstructors = new ArrayList<>();

  private List factoryMethods = new ArrayList<>();

  private Element postConstructMethod;

  private Element preDestroyMethod;

  private final List injectFields = new ArrayList<>();

  private final List interfaceTypes = new ArrayList<>();

  private String addForType;

  private Set importTypes = new TreeSet<>();

  private MethodReader constructor;

  private String registrationTypes;

  private boolean writtenToFile;

  BeanReader(TypeElement beanType, ProcessingContext processingContext) {
    this.beanType = beanType;
    this.shortName = beanType.getSimpleName().toString();
    this.processingContext = processingContext;
    initInterfaces();
    initAddFor();
  }

  private void initAddFor() {
    if (interfaceTypes.size() == 1) {
      addForType = Util.shortName(Util.unwrapProvider(interfaceTypes.get(0)));
    }
  }

  private void initInterfaces() {

    StringBuilder sb = new StringBuilder();

    for (TypeMirror anInterface : beanType.getInterfaces()) {
      String type = Util.unwrapProvider(anInterface.toString());
      interfaceTypes.add(type);
      importTypes.add(type);
      sb.append(", ").append(Util.shortName(type)).append(".class");
    }

    // get class level annotations (that are not Named and Singleton)
    for (AnnotationMirror annotationMirror : beanType.getAnnotationMirrors()) {
      String annotationType = annotationMirror.getAnnotationType().toString();
      if (includeAnnotation(annotationType)) {
        importTypes.add(annotationType);
        sb.append(", ").append(Util.shortName(annotationType)).append(".class");
      }
    }

    registrationTypes = sb.toString();
  }

  TypeElement getBeanType() {
    return beanType;
  }

  String getName() {
    return name;
  }

  Element getPostConstructMethod() {
    return postConstructMethod;
  }

  Element getPreDestroyMethod() {
    return preDestroyMethod;
  }

  List getInjectFields() {
    return injectFields;
  }

  void read(boolean factory) {

    readNamed();

    for (Element element : beanType.getEnclosedElements()) {
      ElementKind kind = element.getKind();
      switch (kind) {
        case CONSTRUCTOR:
          readConstructor(element);
          break;
        case FIELD:
          readField(element);
          break;
        case METHOD:
          readMethod(element, factory);
          break;
      }
    }
    constructor = findConstructor();
    if (constructor != null) {
      constructor.addImports(importTypes);
    }
    for (MethodReader factoryMethod : factoryMethods) {
      factoryMethod.addImports(importTypes);
    }
  }

  private MethodReader findConstructor() {
    if (injectConstructor != null) {
      return injectConstructor;
    }
    if (otherConstructors.size() == 1) {
      return otherConstructors.get(0);
    }
    return null;
  }

  List getDependsOn() {

    List list = new ArrayList<>();
    if (constructor != null) {
      for (MethodReader.MethodParam param : constructor.getParams()) {
        list.add(param.getDependsOn());
      }
    }
    return list;
  }

  List getFactoryMethods() {
    return factoryMethods;
  }

  List getInterfaces() {
    return interfaceTypes;
  }

  /**
   * Return all the interfaces and annotations associated with this bean.
   * 

* The bean is made a 'member' of the list of beans that implement the interface or have the * annotation. *

*/ String getInterfacesAndAnnotations() { return registrationTypes; } private boolean includeAnnotation(String annotationType) { return !EXCLUDED_ANNOTATIONS.contains(annotationType); } private void readNamed() { Named named = beanType.getAnnotation(Named.class); if (named != null) { this.name = named.value(); } } private void readConstructor(Element element) { ExecutableElement ex = (ExecutableElement) element; MethodReader methodReader = new MethodReader(processingContext, ex, beanType, false); methodReader.read(); Inject inject = element.getAnnotation(Inject.class); if (inject != null) { injectConstructor = methodReader; } else { otherConstructors.add(methodReader); } } private void readField(Element element) { Inject inject = element.getAnnotation(Inject.class); if (inject != null) { injectFields.add(new FieldReader(element)); } } private void readMethod(Element element, boolean factory) { ExecutableElement methodElement = (ExecutableElement) element; if (factory) { Bean beanMarker = element.getAnnotation(Bean.class); if (beanMarker != null) { addFactoryMethod(methodElement); } } PostConstruct pcMarker = element.getAnnotation(PostConstruct.class); if (pcMarker != null) { postConstructMethod = element; } PreDestroy pdMarker = element.getAnnotation(PreDestroy.class); if (pdMarker != null) { preDestroyMethod = element; } } private void addFactoryMethod(ExecutableElement methodElement) { MethodReader methodReader = new MethodReader(processingContext, methodElement, beanType, true); methodReader.read(); factoryMethods.add(methodReader); } String getSimpleName() { return beanType.getSimpleName().toString(); } boolean isLifecycleRequired() { return postConstructMethod != null || preDestroyMethod != null; } List createFactoryMethodMeta() { if (factoryMethods.isEmpty()) { return Collections.emptyList(); } List metaList = new ArrayList<>(factoryMethods.size()); for (MethodReader factoryMethod : factoryMethods) { metaList.add(factoryMethod.createMeta()); } return metaList; } MetaData createMeta() { MetaData metaData = new MetaData(beanType.getQualifiedName().toString()); metaData.update(this); return metaData; } boolean isFieldInjectionRequired() { return !injectFields.isEmpty(); } void buildAddFor(Append writer) { writer.append(" if (builder.isAddBeanFor("); if (addForType != null) { writer.append(addForType).append(".class, "); } writer.append(shortName).append(".class)) {").eol(); } private Set importTypes() { if (isLifecycleRequired()) { importTypes.add(Constants.BEAN_LIFECYCLE); } importTypes.add(Constants.GENERATED); importTypes.add(Constants.BUILDER); importTypes.add(beanType.getQualifiedName().toString()); return importTypes; } void writeImports(Append writer) { for (String importType : importTypes()) { writer.append("import %s;", importType).eol(); } writer.eol(); } MethodReader getConstructor() { return constructor; } boolean isWrittenToFile() { return writtenToFile; } void setWrittenToFile() { this.writtenToFile = true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy