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

br.com.objectos.code.pojo.BuilderClass Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Objectos, Fábrica de Software LTDA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package br.com.objectos.code.pojo;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.lang.model.element.Modifier;

import br.com.objectos.code.ConstructorInfo;
import br.com.objectos.code.ParameterInfo;
import br.com.objectos.core.util.MoreCollectors;

import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

/**
 * @author [email protected] (Marcio Endo)
 */
class BuilderClass extends AbstractHasPojoInfo {

  private final List constructorList;

  public BuilderClass(PojoInfo info) {
    super(info);

    List constructorInfoList = constructorInfoList();
    int size = constructorInfoList.size();
    constructorList = constructorInfoList.stream()
        .map(constructor -> new BuilderClassConstructor(constructor, size))
        .collect(MoreCollectors.toImmutableList());
  }

  public JavaFile generate(Configuration configuration) {
    return generate(type(configuration));
  }

  MethodSpec build(Configuration configuration) {
    MethodSpec.Builder b = MethodSpec.methodBuilder("build")
        .addAnnotation(Override.class)
        .addModifiers(Modifier.PUBLIC)
        .returns(naming().superClassTypeNameUnbounded());

    AtomicInteger index = new AtomicInteger();
    List codeBlockList = constructorList.stream()
        .map(constructor -> constructor.build(configuration, index.getAndIncrement()))
        .collect(MoreCollectors.toImmutableList());
    for (CodeBlock codeBlock : codeBlockList) {
      b.addCode(codeBlock);
    }

    return b.build();
  }

  List constructor(Configuration configuration) {
    AtomicInteger index = new AtomicInteger();
    return constructorList.stream()
        .map(constructor -> constructor.constructor(configuration, index.getAndIncrement()))
        .collect(Collectors.toList());
  }

  List field(Configuration configuration) {
    Stream stream0 = configuration.builderClassField();
    Stream stream1 = fieldConstructor();
    Stream stream2 = fieldMethod();
    Stream stream01 = Stream.concat(stream0, stream1);
    return Stream.concat(stream01, stream2).collect(Collectors.toList());
  }

  List getter() {
    return builderMethodStream()
        .map(AttributeMethod::builderClassGetter)
        .collect(Collectors.toList());
  }

  List setter() {
    return builderMethodStream()
        .flatMap(AttributeMethod::builderClassSetter)
        .collect(Collectors.toList());
  }

  TypeSpec type(Configuration configuration) {
    TypeSpec.Builder type = TypeSpec.classBuilder(naming().builderClassSimpleName())
        .addModifiers(Modifier.FINAL)
        .addAnnotation(configuration.annotationSpec())
        .addSuperinterface(naming().builderInterfaceTypeNameUnbounded());

    naming().typeVariableNameListTo(type);

    for (AttributeMethod methodInfo : builderMethodList()) {
      TypeName innerTypeName = naming().builderInnerTypeName(methodInfo);
      type.addSuperinterface(innerTypeName);
    }

    return type
        .addFields(field(configuration))
        .addMethods(constructor(configuration))
        .addMethod(build(configuration))
        .addMethods(setter())
        .addMethods(getter())
        .build();
  }

  private String constructorPrefix(int index) {
    return "___constructor" + index + "___";
  }

  private Stream fieldConstructor() {
    List constructorInfoList = constructorInfoList();
    return constructorInfoList().stream()
        .flatMap(new ConstructorInfoToFieldSpec(constructorInfoList.size()));
  }

  private Stream fieldMethod() {
    return builderMethodStream()
        .map(method -> method.builderClassFieldSpec());
  }

  private class ConstructorInfoToFieldSpec implements Function> {

    private final int size;
    private int index = 0;

    public ConstructorInfoToFieldSpec(int size) {
      this.size = size;
    }

    @Override
    public Stream apply(ConstructorInfo input) {
      Stream parameter = input.parameterInfoStream()
          .map(new ParameterInfoToFieldSpec(index));
      Stream res = Stream.concat(parameter, marker());
      index++;
      return res;
    }

    private Stream marker() {
      if (size == 1) {
        return Stream.empty();
      }

      if (index + 1 == size) {
        return Stream.empty();
      }

      FieldSpec marker = FieldSpec.builder(boolean.class, constructorPrefix(index), Modifier.PRIVATE).build();
      return Stream.of(marker);
    }

  }

  private class ParameterInfoToFieldSpec implements Function {

    private final String prefix;

    public ParameterInfoToFieldSpec(int index) {
      prefix = constructorPrefix(index);
    }

    @Override
    public FieldSpec apply(ParameterInfo input) {
      return input.fieldWriter()
          .modifiers(Modifier.PRIVATE)
          .prefixNameWith(prefix)
          .write();
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy