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

net.zerobuilder.compiler.generate.BuilderContextV Maven / Gradle / Ivy

There is a newer version: 1.603
Show newest version
package net.zerobuilder.compiler.generate;

import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import net.zerobuilder.compiler.generate.DtoRegularGoalContext.ConstructorGoalContext;
import net.zerobuilder.compiler.generate.DtoRegularGoalContext.MethodGoalContext;
import net.zerobuilder.compiler.generate.DtoRegularGoalContext.RegularGoalContext;
import net.zerobuilder.compiler.generate.DtoRegularGoalContext.RegularGoalContextCases;
import net.zerobuilder.compiler.generate.DtoStep.CollectionInfo;
import net.zerobuilder.compiler.generate.DtoStep.RegularStep;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeName.VOID;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static javax.lang.model.element.Modifier.PUBLIC;
import static net.zerobuilder.compiler.generate.DtoGoal.GoalMethodType.INSTANCE_METHOD;
import static net.zerobuilder.compiler.generate.DtoRegularGoalContext.asFunction;
import static net.zerobuilder.compiler.generate.DtoRegularGoalContext.isInstance;
import static net.zerobuilder.compiler.generate.DtoRegularGoalContext.regularSteps;
import static net.zerobuilder.compiler.generate.DtoStep.declaredExceptions;
import static net.zerobuilder.compiler.generate.StepContext.nullCheck;
import static net.zerobuilder.compiler.generate.Utilities.parameterSpec;
import static net.zerobuilder.compiler.generate.Utilities.presentInstances;
import static net.zerobuilder.compiler.generate.Utilities.statement;

final class BuilderContextV {

  static final Function> fields
      = goal -> {
    List builder = new ArrayList<>();
    DtoBuildersContext.BuildersContext buildersContext = DtoRegularGoalContext.buildersContext.apply(goal);
    builder.addAll(isInstance.test(goal)
        ? singletonList(buildersContext.field)
        : emptyList());
    List steps = regularSteps.apply(goal);
    builder.addAll(steps.stream().limit(steps.size() - 1)
        .map(RegularStep::field)
        .collect(Collectors.toList()));
    return builder;
  };

  static final Function> steps
      = goal -> {
    List steps = regularSteps.apply(goal);
    List builder = new ArrayList<>();
    for (RegularStep step : steps.subList(0, steps.size() - 1)) {
      builder.addAll(regularMethods(step, goal, false));
    }
    builder.addAll(regularMethods(steps.get(steps.size() - 1), goal, true));
    return builder;
  };

  private static List regularMethods(
      RegularStep step, RegularGoalContext goal, boolean isLast) {
    List builder = new ArrayList<>();
    builder.add(stepMethod(step, goal, isLast));
    builder.addAll(presentInstances(maybeEmptyCollection(step, goal, isLast)));
    return builder;
  }

  private static MethodSpec stepMethod(RegularStep step, RegularGoalContext goal, boolean isLast) {
    TypeName type = step.validParameter.type;
    String name = step.validParameter.name;
    ParameterSpec parameter = parameterSpec(type, name);
    return methodBuilder(step.validParameter.name)
        .addAnnotation(Override.class)
        .addParameter(parameter)
        .returns(step.nextType)
        .addCode(nullCheck.apply(step))
        .addCode(normalAssignment(step, goal, isLast))
        .addModifiers(PUBLIC)
        .addExceptions(declaredExceptions.apply(step))
        .build();
  }

  private static Optional maybeEmptyCollection(
      RegularStep step, RegularGoalContext goal, boolean isLast) {
    Optional maybeEmptyOption = step.emptyOption();
    if (!maybeEmptyOption.isPresent()) {
      return Optional.empty();
    }
    CollectionInfo collectionInfo = maybeEmptyOption.get();
    return Optional.of(methodBuilder(collectionInfo.name)
        .addAnnotation(Override.class)
        .returns(step.nextType)
        .addCode(emptyCollectionAssignment(step, goal, collectionInfo, isLast))
        .addModifiers(PUBLIC)
        .build());
  }

  private static CodeBlock normalAssignment(RegularStep step, RegularGoalContext goal, boolean isLast) {
    TypeName type = step.validParameter.type;
    String name = step.validParameter.name;
    ParameterSpec parameter = parameterSpec(type, name);
    if (isLast) {
      return regularInvoke.apply(goal);
    } else {
      return CodeBlock.builder()
          .addStatement("this.$N = $N", step.field(), parameter)
          .addStatement("return this")
          .build();
    }
  }

  private static CodeBlock emptyCollectionAssignment(RegularStep step, RegularGoalContext goal,
                                                     CollectionInfo collInfo, boolean isLast) {
    if (isLast) {
      return goal.acceptRegular(emptyCollectionInvoke(step, collInfo));
    } else {
      return CodeBlock.builder()
          .addStatement("this.$N = $L", step.field(), collInfo.initializer)
          .addStatement("return this")
          .build();
    }
  }

  static final Function regularInvoke
      = asFunction(new RegularGoalContextCases() {
    @Override
    public CodeBlock constructorGoal(ConstructorGoalContext goal) {
      CodeBlock parameters = invocationParameters(goal.goal.details.parameterNames);
      return statement("return new $T($L)", goal.goal.details.goalType, parameters);
    }
    @Override
    public CodeBlock methodGoal(MethodGoalContext goal) {
      CodeBlock parameters = invocationParameters(goal.goal.details.parameterNames);
      return methodGoalInvocation(goal, parameters);
    }
  });

  private static RegularGoalContextCases emptyCollectionInvoke(final RegularStep step,
                                                                          final CollectionInfo collectionInfo) {
    return new RegularGoalContextCases() {
      @Override
      public CodeBlock constructorGoal(ConstructorGoalContext goal) {
        CodeBlock parameters = invocationParameters(goal.goal.details.parameterNames);
        TypeName type = step.validParameter.type;
        String name = step.validParameter.name;
        return CodeBlock.builder()
            .addStatement("$T $N = $L", type, name, collectionInfo.initializer)
            .addStatement("return new $T($L)", goal.goal.details.goalType, parameters)
            .build();
      }
      @Override
      public CodeBlock methodGoal(MethodGoalContext goal) {
        CodeBlock parameters = invocationParameters(goal.goal.details.parameterNames);
        TypeName type = step.validParameter.type;
        String name = step.validParameter.name;
        return CodeBlock.builder()
            .addStatement("$T $N = $L", type, name, collectionInfo.initializer)
            .add(methodGoalInvocation(goal, parameters))
            .build();
      }
    };
  }

  private static CodeBlock methodGoalInvocation(MethodGoalContext goal, CodeBlock parameters) {
    CodeBlock.Builder builder = CodeBlock.builder();
    TypeName type = goal.goal.details.goalType;
    String method = goal.goal.details.methodName;
    builder.add(CodeBlock.of(VOID.equals(type) ? "" : "return "));
    builder.add(goal.goal.details.methodType == INSTANCE_METHOD
        ? statement("$N.$N($L)", goal.builders.field, method, parameters)
        : statement("$T.$N($L)", goal.builders.type, method, parameters));
    return builder.build();
  }

  private static CodeBlock invocationParameters(List parameterNames) {
    return CodeBlock.of(String.join(", ", parameterNames));
  }

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy