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

net.beanstandard.compiler.Analyser Maven / Gradle / Ivy

The newest version!
package net.beanstandard.compiler;

import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

import javax.annotation.Generated;
import java.util.Arrays;

import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
import static net.beanstandard.compiler.BeanStandardProcessor.rawType;

final class Analyser {

  private final Model model;
  private final MethodSpec initMethod;
  private final FieldSpec beanField;

  private Analyser(Model model) {
    this.model = model;
    this.beanField = FieldSpec.builder(model.sourceClass(), "bean")
        .addModifiers(PRIVATE)
        .build();
    this.initMethod = initMethod(model, beanField);
  }

  static Analyser create(Model model) {
    return new Analyser(model);
  }

  TypeSpec analyse() {
    TypeSpec.Builder builder = TypeSpec.classBuilder(rawType(model.generatedClass));
    builder.addMethod(builderMethod());
    builder.addMethod(builderMethodWithParam());
    builder.addMethod(perThreadFactoryMethod());
    builder.addMethod(initMethod);
    builder.addMethod(buildMethod());
    builder.addType(PerThreadFactory.create(model, initMethod, beanField)
        .define());
    builder.addField(beanField);
    for (AccessorPair accessorPair : model.accessorPairs) {
      builder.addMethod(setterMethod(accessorPair));
      accessorPair.optionalInfo()
          .filter(OptionalInfo::isRegular)
          .ifPresent(optionalInfo ->
              builder.addMethod(optionalSetterMethod(accessorPair,
                  optionalInfo)));
    }
    return builder.addModifiers(model.maybePublic())
        .addModifiers(FINAL)
        .addMethod(MethodSpec.constructorBuilder()
            .addModifiers(PRIVATE)
            .build())
        .addAnnotation(AnnotationSpec.builder(Generated.class)
            .addMember("value", "$S", BeanStandardProcessor.class.getCanonicalName())
            .build())
        .build();
  }

  private MethodSpec setterMethod(AccessorPair accessorPair) {
    ParameterSpec p = ParameterSpec.builder(accessorPair.propertyType,
        accessorPair.propertyName).build();
    CodeBlock.Builder block = CodeBlock.builder();
    if (accessorPair.setterName().isPresent()) {
      accessorPair.setterName().ifPresent(setterName ->
          block.addStatement("this.$N.$L($N)",
              beanField, setterName, p));
    } else {
      block.addStatement("this.$N.$L().clear()", beanField,
          accessorPair.getterName())
          .addStatement("this.$N.$L().addAll($N)", beanField,
              accessorPair.getterName(), p);
    }
    return MethodSpec.methodBuilder(accessorPair.propertyName)
        .addCode(block.build())
        .addStatement("return this")
        .addParameter(p)
        .addModifiers(model.maybePublic())
        .returns(model.generatedClass)
        .build();
  }

  private MethodSpec optionalSetterMethod(
      AccessorPair accessorPair, OptionalInfo optionalInfo) {
    String setterName = accessorPair.setterName()
        .orElseThrow(AssertionError::new);
    ParameterSpec p = ParameterSpec.builder(optionalInfo.wrapped,
        accessorPair.propertyName).build();
    CodeBlock.Builder block = CodeBlock.builder();
    if (optionalInfo.isOptional()) {
      block.addStatement("this.$N.$L($T.ofNullable($N))",
          beanField, setterName, optionalInfo.wrapper, p);
    } else {
      block.addStatement("this.$N.$L($T.of($N))",
          beanField, setterName, optionalInfo.wrapper, p);
    }
    return MethodSpec.methodBuilder(accessorPair.propertyName)
        .addCode(block.build())
        .addStatement("return this")
        .addParameter(p)
        .addModifiers(model.maybePublic())
        .returns(model.generatedClass)
        .build();
  }

  private MethodSpec builderMethod() {
    ParameterSpec builder = ParameterSpec.builder(model.generatedClass, "builder")
        .build();
    CodeBlock.Builder block = CodeBlock.builder()
        .addStatement("$T $N = new $T()",
            builder.type, builder, model.generatedClass)
        .addStatement("$N.$N = new $T()",
            builder, beanField, model.sourceClass());
    for (AccessorPair accessorPair : model.accessorPairs) {
      accessorPair.optionalInfo().ifPresent(optionalInfo -> {
        String setterName = accessorPair.setterName()
            .orElseThrow(AssertionError::new);
        block.addStatement("$N.$N.$L($T.empty())",
            builder, beanField, setterName, optionalInfo.wrapper);
      });
    }
    return MethodSpec.methodBuilder("builder")
        .addModifiers(STATIC)
        .addCode(block.build())
        .addStatement("return $N", builder)
        .returns(model.generatedClass)
        .build();
  }

  private MethodSpec builderMethodWithParam() {
    ParameterSpec builder = ParameterSpec.builder(model.generatedClass, "builder").build();
    ParameterSpec input = ParameterSpec.builder(model.sourceClass(), "input").build();
    CodeBlock.Builder block = CodeBlock.builder()
        .addStatement("$T $N = new $T()", builder.type, builder, model.generatedClass)
        .addStatement("$N($N, $N)", initMethod, builder, input)
        .addStatement("return $N", builder);
    return MethodSpec.methodBuilder("builder")
        .addCode(block.build())
        .addParameter(input)
        .addModifiers(STATIC)
        .returns(model.generatedClass)
        .build();
  }

  private static MethodSpec initMethod(Model model, FieldSpec beanField) {
    ParameterSpec builder = ParameterSpec.builder(model.generatedClass, "builder").build();
    ParameterSpec input = ParameterSpec.builder(model.sourceClass(), "input").build();
    CodeBlock.Builder block = CodeBlock.builder();
    block.addStatement("$N.$N = new $T()", builder, beanField,
        model.sourceClass());
    for (AccessorPair accessorPair : model.accessorPairs) {
      block.addStatement("$N.$N($N.$L())", builder, accessorPair.propertyName,
          input, accessorPair.getterName());
    }
    return MethodSpec.methodBuilder("init")
        .addCode(block.build())
        .addParameters(Arrays.asList(builder, input))
        .addModifiers(PRIVATE, STATIC)
        .build();
  }

  private MethodSpec buildMethod() {
    ParameterSpec result = ParameterSpec.builder(model.sourceClass(), "result").build();
    return MethodSpec.methodBuilder("build")
        .addStatement("$T $N = this.$N", model.sourceClass(), result, beanField)
        .addStatement("this.$N = null", beanField)
        .addStatement("return $N", result)
        .returns(model.sourceClass())
        .addModifiers(model.maybePublic())
        .build();
  }

  private MethodSpec perThreadFactoryMethod() {
    MethodSpec.Builder builder = MethodSpec.methodBuilder("perThreadFactory")
        .returns(model.perThreadFactoryClass())
        .addModifiers(STATIC);
    return builder.addStatement("return new $T()",
        model.perThreadFactoryClass())
        .build();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy