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

merger.CodeSnipitReader 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 2019 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 merger;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParseStart;
import com.github.javaparser.Provider;
import com.github.javaparser.Providers;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;

import configuration.PathConverter;
import generator.CodeSnipit;
import reader.Parser;

/**
 * Reads a {@link CodeSnipit} and turns it into a {@link CompilationUnit} by using {@link JavaParser}.
 *
 * @author Daan
 */
public class CodeSnipitReader {

  /**
   * Reads a {@link CodeSnipit} and turns it into a {@link CompilationUnit} by using {@link JavaParser}.
   *
   * @param codeSnipit The {@link CodeSnipit} to be read.
   * @param classPath The path to the class to which this is going to be merged. Needed to append the class name if the {@link CodeSnipit} has no class name
   *          defined.
   * @return A {@link CompilationUnit} of the input code
   */
  public CompilationUnit read(CodeSnipit codeSnipit, String classPath) {
    CompilationUnit n;
    if (hasClassCodeDefined(codeSnipit)) {
      String completeClass = toCompleteClass(codeSnipit, classPath);
      n = readClass(completeClass);
    } else {
      // TODO handle it if there is javadoc defined above the package
      CompilationUnit cu = new CompilationUnit();

      String string = codeSnipit.toString();

      int lineBegin = getFirstIndexAfterComment(string);
      int lineEnd = lineBegin + string.substring(lineBegin).indexOf(";");
      lineEnd = lineEnd < 0 ? string.length() : (lineEnd + 1);
      String declaration = string.substring(lineBegin, lineEnd);

      boolean endOfFile = false;

      // Add package if present
      ParseResult pack = parsePackage(declaration);
      if (pack.isSuccessful()) {
        cu.setPackageDeclaration(pack.getResult().get());

        endOfFile = lineEnd == string.length();

        if (!endOfFile) {
          lineBegin = lineEnd + 1;
          lineEnd = lineBegin + string.substring(lineBegin).indexOf(";");
          lineEnd = lineEnd < 0 ? string.length() : (lineEnd + 1);
          declaration = string.substring(lineBegin, lineEnd);
        }
      }

      // Add imports
      declaration = string.substring(lineBegin, lineEnd);
      ParseResult result = parseImport(declaration);
      while (result.isSuccessful() && !endOfFile) {
        cu.addImport(result.getResult().get());

        endOfFile = lineEnd == string.length();
        if (!endOfFile) {
          lineBegin = lineEnd + 1;
          lineEnd = lineBegin + string.substring(lineBegin).indexOf(";");
          lineEnd = lineEnd < 0 ? string.length() : (lineEnd + 1);
          declaration = string.substring(lineBegin, lineEnd);
          result = parseImport(declaration);
        }
      }

      n = cu;
    }
    return n;
  }

  /**
   * Converts a {@link CodeSnipit} to a String representing a full class. If the codeSnipit does not have a class defined, the code is wrapped into a class
   * taking into account possible imports or package definition.
   *
   * @param codeSnipit The {@link CodeSnipit} to convert.
   * @param mergeClassPath The path to the class to which this will eventually be merged. Needed to determine the class name if the codeSnipit does not contain
   *          one.
   * @return A String representing a full class.
   */
  public String toCompleteClass(CodeSnipit codeSnipit, String mergeClassPath) {
    String string = codeSnipit.toString();
    int index = firstIndexAfterImports(string);

    StringBuilder code = new StringBuilder();
    code.append(string.substring(0, index));
    boolean hasClassDefined = hasClassDefined(string.substring(index));
    if (!hasClassDefined) {
      // Don't add any lines otherwise the CodeSnipitInserter cannot know the line number anymore
      code.append("public class " + PathConverter.toClassName(mergeClassPath) + " {");
    }
    code.append(string.substring(index));
    if (!hasClassDefined) {
      code.append("\n}");
    }
    return code.toString();
  }

  /**
   * @param codeSnipit The code to analyze
   * @return True if it has a class defined or fields, constructors or methods that should have been in the class.
   */
  private boolean hasClassCodeDefined(CodeSnipit codeSnipit) {
    String string = codeSnipit.toString();
    int index = firstIndexAfterImports(string);
    String codeAfterImports = string.substring(index);
    return hasClassDefined(codeAfterImports) || codeAfterImports.contains(";");
  }

  protected CompilationUnit readClass(String completeClass) {
    CompilationUnit cu = Parser.parse(completeClass);
    // Needed to preserve the original formatting
    LexicalPreservingPrinter.setup(cu);
    return cu;
  }

  protected CompilationUnit read(String className) throws IOException {
    CompilationUnit cu = null;
    try (FileInputStream in = new FileInputStream(className)) {
      cu = JavaParser.parse(in);
      in.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
    // Needed to preserve the original formatting
    LexicalPreservingPrinter.setup(cu);
    return cu;
  }

  protected int firstIndexAfterImports(String string) {
    int lineBegin = getFirstIndexAfterComment(string);
    int lineEnd = lineBegin + string.substring(lineBegin).indexOf(";");
    lineEnd = lineEnd < 0 ? string.length() : (lineEnd + 1);
    String declaration = string.substring(lineBegin, lineEnd);

    ParseResult result = parsePackage(declaration);
    if (!result.isSuccessful()) {
      result = parseImport(declaration);
    }

    while (result.isSuccessful()) {
      if (lineEnd == string.length()) {
        lineBegin = lineEnd;
        break;
      }
      lineBegin = lineEnd + 1;
      lineEnd = lineBegin + string.substring(lineBegin).indexOf(";");
      lineEnd = lineEnd < 0 ? string.length() : (lineEnd + 1);
      declaration = string.substring(lineBegin, lineEnd);
      result = parseImport(declaration);

    }

    // TODO replace 'lineEnd + 1' with 'lineEnd'

    lineBegin = getIndexAfterNewLine(string, lineBegin);

    return lineBegin;
  }

  private int getIndexAfterNewLine(String string, int lineBegin) {
    int index = getIndexAfterNewLine(string, lineBegin, "\r");
    index = getIndexAfterNewLine(string, index, "\n");
    return index;
  }

  private int getIndexAfterNewLine(String string, int lineBegin, String newLineIndicator) {
    int newLine = string.substring(lineBegin).indexOf(newLineIndicator);
    int index = lineBegin;
    if (0 <= newLine && newLine < 3) {
      index = index + newLine + 1;
    }
    return index;
  }

  protected int getFirstIndexAfterComment(String string) {
    int index = 0;
    if (string.startsWith("/*")) {
      index = string.indexOf("*/") + 3;
    }
    return index;
  }

  protected ParseResult parsePackage(String declaration) {
    return parseDeclaration(declaration, ParseStart.PACKAGE_DECLARATION);
  }

  protected ParseResult parseImport(String declaration) {
    return parseDeclaration(declaration, ParseStart.IMPORT_DECLARATION);
  }

  protected boolean hasClassDefined(String string) {
    return parseDeclaration(string, ParseStart.COMPILATION_UNIT).isSuccessful();
  }

  private  ParseResult parseDeclaration(String declaration, ParseStart parseStart) {
    JavaParser parser = new JavaParser();
    Provider provider = Providers.provider(declaration);
    ParseResult result = parser.parse(parseStart, provider);
    return result;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy