merger.CodeSnipitReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JavaForger Show documentation
Show all versions of JavaForger Show documentation
JavaForger can create source code from templates using existing java classes as input.
/*
* 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