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

initialization.InitializationService Maven / Gradle / Ivy

Go to download

JavaForger can create source code from templates using existing java classes as input.

There is a newer version: 2.0.1
Show newest version
/*
 * Copyright 2018 by Daan van den Heuvel.
 *
 * This file is part of JavaForger.
 *
 * 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 initialization;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import templateInput.ClassContainer;
import templateInput.definition.InitializedTypeDefinition;
import templateInput.definition.MethodDefinition;
import templateInput.definition.VariableDefinition;

/**
 * Class for initializing {@link VariableDefinition} for creating java code or unit tests from templates.
 *
 * @author Daan
 */
public class InitializationService {

  private InitDefaultValues defaults = new InitDefaultValues();
  private InitConverter converter = new InitConverter();

  public void init(ClassContainer claz) {
    converter.reset();
    initVariables(claz.getFields());
    initMethods(claz.getMethods());
    initMethods(claz.getConstructors());
  }

  public void init(InitializedTypeDefinition var) {
    converter.reset();
    initialize(var);
  }

  private void initialize(InitializedTypeDefinition var) {
    if (defaults.containsDefaultValue(var.getType().toString())) {
      setDefaultInit1(var);
      setDefaultInit2(var);
      setNoInit(var);
    } else if (var.getType().toString().contains("<")) {
      initParameterized(var);
    } else {
      // TODO the stuff below should be replaced by a call to the Generator with a custom "builderUsage.javat" file defining the start and end of a builder.
      String init = var.getType() + ".builder().build()";
      var.setInit1(init);
      var.setInit2(init);
      var.setNoInit(defaults.getNoInitFor(var.getType().toString()));
    }
    var.setDefaultInit(defaults.containsEmptyInit(var.getTypeWithoutParameters()) ? defaults.getEmptyInit(var.getTypeWithoutParameters()).getValue() : null);
    var.setCollection(defaults.isCollection(var.getTypeWithoutParameters()));
  }

  private void initMethods(List methods) {
    methods.stream().forEach(this::initialize);
    methods.forEach(m -> initVariables(m.getParameters()));
  }

  private void initVariables(List list) {
    list.stream().forEach(this::initialize);
  }

  private void setNoInit(InitializedTypeDefinition var) {
    if (defaults.containsTestNoInit(var.getType().toString())) {
      InitValue value = defaults.getTestNoInit(var.getType().toString());
      var.setNoInit(value.getValue());
      var.addInitImports(value.getImports());
    } else {
      var.setNoInit("null");
    }
  }

  private void setDefaultInit1(InitializedTypeDefinition var) {
    if (defaults.containsDefaultValue(var.getType().toString())) {
      InitValue value = defaults.getDefaultValue1(var.getType().toString());
      var.setInit1(converter.convert(value.getValue()));
      var.addInitImports(value.getImports());
    }
  }

  private void setDefaultInit2(InitializedTypeDefinition var) {
    if (defaults.containsDefaultValue(var.getType().toString())) {
      InitValue value = defaults.getDefaultValue2(var.getType().toString());
      var.setInit2(converter.convert(value.getValue()));
      var.addInitImports(value.getImports());
    }
  }

  private void initParameterized(InitializedTypeDefinition var) {
    String mainType = var.getTypeWithoutParameters();
    StringBuilder sb1 = new StringBuilder();
    StringBuilder sb2 = new StringBuilder();
    if (defaults.isParameterizedVariable(mainType)) {
      InitValue value = defaults.getParameterizedVariable(mainType);
      sb1.append(value.getValue());
      sb2.append(value.getValue());
      var.addInitImports(value.getImports());
      List subTypes = getSubTypes(var);

      String init1 = subTypes.stream().map(VariableDefinition::getInit1).collect(Collectors.joining(", "));
      String init2 = subTypes.stream().map(VariableDefinition::getInit2).collect(Collectors.joining(", "));

      sb1.append(init1 + ")");
      sb2.append(init2 + ")");

      subTypes.stream().forEach(v -> var.addInitImports(v.getInitImports()));

    } else {
      sb1.append(mainType + ".builder().build()");
      sb2.append(mainType + ".builder().build()");
    }
    var.setInit1(sb1.toString());
    var.setInit2(sb2.toString());
    var.setNoInit(defaults.getNoInitFor(mainType));
  }

  private List getSubTypes(InitializedTypeDefinition var) {
    int indexOf = var.getType().toString().indexOf("<");
    String subString = var.getType().toString().substring(indexOf + 1, var.getType().toString().length() - 1);
    List subVariableTypes = splitSubTypes(subString);
    List subTypes =
        subVariableTypes.stream().map(subType -> VariableDefinition.builder().withType(subType).build()).collect(Collectors.toList());
    // This is a recursive call, to the caller
    subTypes.forEach(subVar -> initialize(subVar));
    return subTypes;
  }

  /**
   * This method receives the inner type of a parmeterized type (e.g. 'InnerType1, ? extends InnerType2' which originates from 'ParameterizedType'). All comma-seperated types are then split into subStrings and returned. This method does not split any inner parameterized types,
   * this should be done by recursively calling this method on inner types.
   *
   * @param type The comma-separated inner type of a parameterized type.
   * @return
   */
  private List splitSubTypes(String type) {
    List subVariableTypes = new ArrayList<>();
    int withinBrackets = 0;
    StringBuilder currentVar = new StringBuilder();

    for (char c : type.toCharArray()) {
      if (withinBrackets > 0) {
        currentVar.append(c);
        if (c == '>') {
          withinBrackets--;
          if (withinBrackets <= 0) {
            subVariableTypes.add(currentVar.toString());
            currentVar = new StringBuilder();
          }
        }
      } else if (c == '<') {
        currentVar.append(c);
        withinBrackets++;
      } else if (Character.isLetter(c) || Character.isDigit(c)) {
        currentVar.append(c);
      } else if (c == '?') {
        // This has to be added so that the if statement checking 'extends' can safely remove it.
        subVariableTypes.add("?");
      } else if (currentVar.length() > 0) {
        String current = currentVar.toString();
        if (current.equals("extends")) {
          // We do not want to store extends
          // If this variable is the keyword extends, then the previous variable does not define a type
          subVariableTypes.remove(subVariableTypes.size() - 1);
          currentVar = new StringBuilder();
        } else {
          subVariableTypes.add(current);
          currentVar = new StringBuilder();
        }
      }
    }

    if (currentVar.length() > 0) {
      subVariableTypes.add(currentVar.toString());
    }
    return subVariableTypes;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy