reader.ClassContainerReader 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 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 reader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import configuration.StaticJavaForgerConfiguration;
import generator.JavaForgerException;
import templateInput.ClassContainer;
import templateInput.definition.ClassDefinition;
import templateInput.definition.MethodDefinition;
import templateInput.definition.TypeDefinition;
import templateInput.definition.VariableDefinition;
/**
* Reader for all data within a class.
*
* @author Daan
*/
public class ClassContainerReader {
private StaticJavaForgerConfiguration staticConfig = StaticJavaForgerConfiguration.getConfig();
public ClassContainer read(String inputClass) throws IOException {
CompilationUnit cu = getCompilationUnit(inputClass);
return readCompilationUnit(cu);
}
private CompilationUnit getCompilationUnit(String inputClass) throws IOException {
CompilationUnit cu = null;
try (FileInputStream in = new FileInputStream(inputClass)) {
cu = JavaParser.parse(in);
in.close();
} catch (FileNotFoundException e) {
throw new JavaForgerException(e, "Could not parse " + inputClass);
}
return cu;
}
private ClassContainer readCompilationUnit(CompilationUnit cu) {
ClassContainer claz = new ClassContainer();
List fields = new ArrayList<>();
List methods = new ArrayList<>();
List constructors = new ArrayList<>();
for (TypeDeclaration> type : cu.getTypes()) {
if (type instanceof ClassOrInterfaceDeclaration) {
claz = parseClass(type);
}
List childNodes = type.getChildNodes();
for (Node node : childNodes) {
if (node instanceof FieldDeclaration) {
fields.add(parseField(node));
} else if (node instanceof MethodDeclaration) {
methods.add(parseMethod(node));
} else if (node instanceof ConstructorDeclaration) {
constructors.add(parseConstructor(node));
}
}
}
Optional typeImport = cu.getPackageDeclaration().map(pd -> pd.getNameAsString());
if (typeImport.isPresent()) {
claz.addTypeImport(typeImport.get() + "." + claz.getName());
constructors.forEach(c -> c.addTypeImport(typeImport.get()));
}
claz.setFields(fields);
claz.setMethods(methods);
claz.setConstructors(constructors);
return claz;
}
private ClassContainer parseClass(TypeDeclaration> type) {
ClassOrInterfaceDeclaration cd = (ClassOrInterfaceDeclaration) type;
Set annotations = cd.getAnnotations().stream().map(annotation -> annotation.getName().toString()).collect(Collectors.toSet());
Set accessModifiers = cd.getModifiers().stream().map(modifier -> modifier.asString()).collect(Collectors.toSet());
List interfaces = cd.getImplementedTypes().stream().map(i -> i.getNameAsString()).collect(Collectors.toList());
String extend = cd.getExtendedTypes().stream().findFirst().map(e -> e.getNameAsString()).orElse(null);
ClassDefinition def = ClassDefinition.builder().withName(cd.getNameAsString()).withType(cd.getNameAsString())
.withLineNumber(cd.getBegin().map(p -> p.line).orElse(-1)).withColumn(cd.getBegin().map(p -> p.column).orElse(-1)).withAnnotations(annotations)
.withAccessModifiers(accessModifiers).withExtend(extend).withInterfaces(interfaces).build();
return new ClassContainer(def);
}
private MethodDefinition parseMethod(Node node) {
MethodDeclaration md = (MethodDeclaration) node;
MethodDefinition method = parseCallable(md);
method.setType(md.getTypeAsString());
resolveAndSetImport(md.getType(), method);
return method;
}
private MethodDefinition parseConstructor(Node node) {
ConstructorDeclaration md = (ConstructorDeclaration) node;
MethodDefinition method = parseCallable(md);
method.setType(md.getNameAsString());
return method;
}
private MethodDefinition parseCallable(CallableDeclaration> md) {
Set accessModifiers = md.getModifiers().stream().map(Modifier::asString).collect(Collectors.toSet());
Set annotations = md.getAnnotations().stream().map(AnnotationExpr::getNameAsString).collect(Collectors.toSet());
return MethodDefinition.builder().withName(md.getNameAsString()).withAccessModifiers(accessModifiers).withAnnotations(annotations)
.withLineNumber(md.getBegin().map(p -> p.line).orElse(-1)).withColumn(md.getBegin().map(p -> p.column).orElse(-1)).withParameters(getParameters(md))
.build();
}
private VariableDefinition parseField(Node node) {
FieldDeclaration fd = (FieldDeclaration) node;
Set annotations = fd.getAnnotations().stream().map(annotation -> annotation.getName().toString()).collect(Collectors.toSet());
Set accessModifiers = fd.getModifiers().stream().map(modifier -> modifier.asString()).collect(Collectors.toSet());
Optional originalInit = depthFirstSearch(fd, Expression.class);
VariableDefinition variable = VariableDefinition.builder().withName(fd.getVariable(0).getName().asString()).withType(fd.getElementType().asString())
.withAnnotations(annotations).withLineNumber(fd.getBegin().map(p -> p.line).orElse(-1)).withColumn(fd.getBegin().map(p -> p.column).orElse(-1))
.withAccessModifiers(accessModifiers).originalInit(originalInit.orElse(null)).build();
resolveAndSetImport(fd.getElementType(), variable);
return variable;
}
private Optional depthFirstSearch(Node node, Class claz) {
if (claz.isAssignableFrom(node.getClass())) {
return Optional.of(node.toString());
}
return node.getChildNodes().stream().map(n -> depthFirstSearch(n, claz)).filter(Optional::isPresent).map(Optional::get).map(Object::toString).findFirst();
}
private List getParameters(CallableDeclaration> md) {
LinkedHashMap params = new LinkedHashMap<>();
md.getParameters().stream().forEach(p -> params.put(p, VariableDefinition.builder().withName(p.getNameAsString()).withType(p.getTypeAsString()).build()));
params.entrySet().forEach(p -> resolveAndSetImport(p.getKey().getType(), p.getValue()));
List parameters = params.values().stream().collect(Collectors.toList());
return parameters;
}
private void resolveAndSetImport(Type type, TypeDefinition variable) {
List imports = resolve(type);
if (!imports.isEmpty()) {
imports.stream().filter(s -> !s.contains("?")).forEach(s -> variable.addTypeImport(s));
}
}
private List resolve(Type type) {
List imports = new ArrayList<>();
if (staticConfig.getSymbolSolver() != null) {
try {
ResolvedType resolve = type.resolve();
imports.addAll(getImportsFromResolvedType(resolve));
} catch (@SuppressWarnings("unused") Exception e) {
System.err.println("FieldReader: Could not resolve import for " + type.asString());
}
}
return imports;
}
private List getImportsFromResolvedType(ResolvedType resolve) {
List imports = new ArrayList<>();
String imp;
if (resolve.isReferenceType()) {
ResolvedReferenceType refType = resolve.asReferenceType();
ResolvedReferenceTypeDeclaration type = refType.getTypeDeclaration();
imp = type.getQualifiedName();
List innerResolvedTypes =
type.getTypeParameters().stream().map(tp -> refType.typeParametersMap().getValue(tp)).collect(Collectors.toList());
// This is a recursive call to resolve all imports of parameterized types
List collect = innerResolvedTypes.stream().flatMap(t -> getImportsFromResolvedType(t).stream()).collect(Collectors.toList());
imports.addAll(collect);
} else {
imp = resolve.describe();
}
if (!imp.startsWith("java.lang.") && !resolve.isPrimitive()) {
imports.add(imp);
}
return imports;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy