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

net.zerobuilder.compiler.analyse.Analyser Maven / Gradle / Ivy

There is a newer version: 1.644
Show newest version
package net.zerobuilder.compiler.analyse;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import net.zerobuilder.Builder;
import net.zerobuilder.Updater;
import net.zerobuilder.compiler.analyse.DtoGoalElement.AbstractGoalElement;
import net.zerobuilder.compiler.analyse.DtoGoalElement.AbstractRegularGoalElement;
import net.zerobuilder.compiler.analyse.DtoGoalElement.BeanGoalElement;
import net.zerobuilder.compiler.analyse.DtoGoalElement.ModuleChoice;
import net.zerobuilder.compiler.common.LessElements;
import net.zerobuilder.compiler.generate.DtoContext.GoalContext;
import net.zerobuilder.compiler.generate.DtoGeneratorInput.AbstractGoalInput;
import net.zerobuilder.compiler.generate.DtoGeneratorInput.BeanGoalInput;
import net.zerobuilder.compiler.generate.DtoGeneratorInput.GeneratorInput;
import net.zerobuilder.compiler.generate.DtoGeneratorInput.ProjectedGoalInput;
import net.zerobuilder.compiler.generate.DtoGeneratorInput.RegularSimpleGoalInput;
import net.zerobuilder.compiler.generate.DtoModule.BeanModule;
import net.zerobuilder.compiler.generate.DtoModule.ProjectedModule;
import net.zerobuilder.compiler.generate.DtoModule.RegularSimpleModule;
import net.zerobuilder.modules.builder.RegularBuilder;
import net.zerobuilder.modules.builder.bean.BeanBuilder;
import net.zerobuilder.modules.generics.GenericsBuilder;
import net.zerobuilder.modules.updater.RegularUpdater;
import net.zerobuilder.modules.updater.bean.BeanUpdater;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import java.util.List;
import java.util.function.Function;

import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
import static javax.lang.model.element.ElementKind.METHOD;
import static javax.lang.model.element.Modifier.STATIC;
import static net.zerobuilder.Style.IMMUTABLE;
import static net.zerobuilder.compiler.Messages.ErrorMessages.BEAN_SUBGOALS;
import static net.zerobuilder.compiler.analyse.DtoGoalElement.goalElementCases;
import static net.zerobuilder.compiler.analyse.DtoGoalElement.regularGoalElementCases;
import static net.zerobuilder.compiler.analyse.MoreValidations.checkAccessLevel;
import static net.zerobuilder.compiler.analyse.MoreValidations.checkNameConflict;
import static net.zerobuilder.compiler.analyse.ProjectionValidatorB.validateBean;
import static net.zerobuilder.compiler.analyse.ProjectionValidatorV.validateBuilder;
import static net.zerobuilder.compiler.analyse.ProjectionValidatorV.validateUpdater;
import static net.zerobuilder.compiler.analyse.TypeValidator.validateContextClass;
import static net.zerobuilder.compiler.analyse.Utilities.peer;
import static net.zerobuilder.compiler.common.LessTypes.asTypeElement;
import static net.zerobuilder.compiler.generate.DtoContext.createContext;
import static net.zerobuilder.compiler.generate.ZeroUtil.flatList;
import static net.zerobuilder.compiler.generate.ZeroUtil.parameterizedTypeName;
import static net.zerobuilder.compiler.generate.ZeroUtil.rawClassName;
import static net.zerobuilder.compiler.generate.ZeroUtil.transform;

public final class Analyser {

  private static final RegularSimpleModule BUILDER = new RegularBuilder();
  private static final BeanModule BEAN_BUILDER = new BeanBuilder();
  private static final ProjectedModule UPDATER = new RegularUpdater();
  private static final BeanModule BEAN_UPDATER = new BeanUpdater();
  private static final RegularSimpleModule GENERICS = new GenericsBuilder();

  public static GeneratorInput analyse(TypeElement tel) throws ValidationException {
    validateContextClass(tel);
    TypeName type = parameterizedTypeName(ClassName.get(tel),
        transform(tel.getTypeParameters(), TypeVariableName::get));
    ClassName generatedType = peer(rawClassName(type), "Builders");
    GoalContext context = createContext(type, generatedType);
    List goals = goals(tel, context);
    checkNameConflict(goals);
    checkAccessLevel(goals);
    List descriptions = transform(goals, description);
    return GeneratorInput.create(context, descriptions);
  }

  private static final Function description =
      goalElementCases(
          regularGoalElementCases(
              general -> hasTypevars(general.executableElement) || general.style == IMMUTABLE ?
                  new RegularSimpleGoalInput(GENERICS, validateBuilder.apply(general)) :
                  new RegularSimpleGoalInput(BUILDER, validateBuilder.apply(general)),
              projected -> new ProjectedGoalInput(UPDATER, validateUpdater.apply(projected))),
          bean -> bean.moduleChoice == ModuleChoice.BUILDER ?
              new BeanGoalInput(BEAN_BUILDER, validateBean.apply(bean)) :
              new BeanGoalInput(BEAN_UPDATER, validateBean.apply(bean)));

  private static List goals(TypeElement tel, GoalContext context) {
    return tel.getAnnotation(net.zerobuilder.BeanBuilder.class) != null ?
        beanGoals(tel, context) :
        regularGoals(tel, context);
  }

  private static boolean hasTypevars(ExecutableElement element) {
    if (!element.getTypeParameters().isEmpty()) {
      return true;
    }
    return !element.getModifiers().contains(STATIC) &&
        !asTypeElement(element.getEnclosingElement().asType()).getTypeParameters().isEmpty();
  }

  private static List regularGoals(TypeElement tel, GoalContext context) {
    return tel.getEnclosedElements().stream()
        .filter(el -> el.getAnnotation(Builder.class) != null || el.getAnnotation(Updater.class) != null)
        .filter(el -> el.getKind() == CONSTRUCTOR || el.getKind() == METHOD)
        .map(LessElements::asExecutable)
        .map(DtoGoalElement.createRegular(context))
        .collect(flatList());
  }

  private static List beanGoals(TypeElement buildElement, GoalContext context) {
    buildElement.getEnclosedElements().stream()
        .filter(el -> el.getAnnotation(Builder.class) != null || el.getAnnotation(Updater.class) != null)
        .findAny()
        .ifPresent(el -> {
          throw new ValidationException(BEAN_SUBGOALS, el);
        });
    return BeanGoalElement.create(buildElement, context);
  }

  private Analyser() {
    throw new UnsupportedOperationException("no instances");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy