org.nuiton.jaxx.compiler.java.JavaFile Maven / Gradle / Ivy
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.compiler.java;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.eugene.java.extension.ImportsManager;
import org.nuiton.jaxx.compiler.finalizers.JAXXCompilerFinalizer;
import org.nuiton.jaxx.compiler.types.TypeManager;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A Java source file being generated for output. Once the class is completely initialized, use the
* {@link #toString} method to generate source code for it.
*/
public class JavaFile extends JavaElement {
/** Logger. */
static final Logger log = LogManager.getLogger(JavaFile.class);
protected static final String GETTER_PATTERN = "return %1$s;";
protected static final String BOOLEAN_GETTER_PATTERN = "return %1$s !=null && %1$s;";
protected static final String SETTER_PATTERN = "%1$s oldValue = this.%2$s;\nthis.%2$s = %2$s;\nfirePropertyChange(%3$s, oldValue, %2$s);";
private Set imports = new HashSet<>();
private List fields = new ArrayList<>();
private List methods = new ArrayList<>();
private List constructors = new ArrayList<>();
private final List innerClasses = new ArrayList<>();
private String superClass;
private List interfaces;
private final StringBuilder rawBodyCode = new StringBuilder();
private boolean superclassIsJAXXObject;
private boolean abstractClass;
private String genericType;
private String superGenericType;
private final ImportsManager importManager;
private String simpleName;
JavaFile(int modifiers, String packageName,String className) {
super(modifiers, packageName+"."+className);
importManager = new ImportsManager();
// add the fqn before all in the import manager to deal with alias classes
importManager.addImport(packageName+"."+className);
setSimpleName(className);
}
JavaFile(int modifiers, String className) {
super(modifiers, className);
importManager = new ImportsManager();
// add the fqn before all in the import manager to deal with alias classes
importManager.addImport(className);
}
public String getPackageName() {
String name = getName();
String packageName;
if (name.contains(".")) {
packageName = name.substring(0, name.lastIndexOf("."));
} else {
packageName = null;
}
return packageName;
}
public ImportsManager getImportManager() {
return importManager;
}
public String getImportedType(Class> type) {
return getImportManager().getType(type);
}
public String getImportedType(String type) {
return getImportManager().getType(type);
}
public String[] getImports() {
List result = new ArrayList<>(imports);
Collections.sort(result);
return result.toArray(new String[result.size()]);
}
public List getImportsList() {
List result = new ArrayList<>(imports);
Collections.sort(result);
return result;
}
public String getSuperClass() {
return superClass;
}
public List getInterfaces() {
if (interfaces == null) {
interfaces = new ArrayList<>();
}
return interfaces;
}
public List getMethods() {
return methods;
}
public List getFields() {
return fields;
}
public boolean isAbstractClass() {
return abstractClass;
}
public String getGenericType() {
return genericType;
}
public List getInnerClasses() {
return innerClasses;
}
public StringBuilder getRawBodyCode() {
return rawBodyCode;
}
public String getSuperGenericType() {
return superGenericType;
}
public boolean isSuperclassIsJAXXObject() {
return superclassIsJAXXObject;
}
public String getSimpleName() {
return simpleName;
}
public JavaField getField(String componentId) {
for (JavaField field : fields) {
if (componentId.equals(field.getName())) {
return field;
}
}
return null;
}
public void addImport(String importString) {
try {
importManager.addImport(importString);
} catch (Exception e) {
log.error("Could not determine simple name of import " + importString);
}
}
public void addImport(Class> importString) {
addImport(importString.getName());
}
public void setImports(Collection imports) {
this.imports = new HashSet<>(imports);
}
public void setGenericType(String genericType) {
this.genericType = genericType;
}
public void setSuperClass(String superClass) {
this.superClass = superClass;
}
public void addInterface(String... canonicalNames) {
if (canonicalNames == null) {
return;
}
for (String canonicalName : canonicalNames) {
if (interfaces == null || !interfaces.contains(canonicalName)) {
getInterfaces().add(canonicalName);
}
}
}
public void setInterfaces(List interfaces) {
List simpleInterfaces = new ArrayList<>();
for (String anInterface : interfaces) {
try {
anInterface = importManager.getType(anInterface);
} catch (Exception e) {
log.error("Could not determine simple name of interface " +
anInterface);
}
simpleInterfaces.add(anInterface);
}
this.interfaces = simpleInterfaces;
}
public void addConstructor(JavaConstructor constructor) {
constructors.add(constructor);
}
public void addMethod(JavaMethod method) {
String returnType = method.getReturnType();
try {
String type = importManager.getReturnType(returnType);
method.setReturnType(type);
} catch (Exception e) {
log.error("Could not determine simple name of return type " +
returnType + " for method " + method.getName());
}
for (JavaArgument argument : method.getArguments()) {
String argumentType = argument.getType();
try {
String type = importManager.getType(argumentType);
argument.setType(type);
} catch (Exception e) {
log.error("Could not determine simple name of argument type " +
argumentType + " of argument " + argument.getName() +
" for method " + method.getName());
}
}
String[] exceptions = method.getExceptions();
for (int i = 0, length = exceptions.length; i < length; i++) {
String exception = exceptions[i];
try {
String exceptionSimple = importManager.getType(exception);
exceptions[i] = exceptionSimple;
} catch (Exception e) {
log.error("Could not determine simple name of exception " +
exception + " for method " + method.getName());
}
}
// this is a mreal method
methods.add(method);
}
public void addField(JavaField field) {
addField(field, false);
}
public JavaMethod addGetterMethod(String id,
int modifiers,
String type,
boolean override,
boolean useOverride) {
String capitalizedName = StringUtils.capitalize(id);
String methodName = "get" + capitalizedName;
String bodyCode;
if (useOverride) {
bodyCode = "super." + methodName + "()";
} else {
bodyCode = id;
}
String content = String.format(GETTER_PATTERN, bodyCode);
JavaMethod method = JavaElementFactory.newMethod(modifiers,
type,
methodName,
content,
override
);
addMethod(method);
return method;
}
public JavaMethod addAbstractGetterMethod(String id,
int modifiers,
String type,
boolean override) {
String capitalizedName = StringUtils.capitalize(id);
String methodName = "get" + capitalizedName;
JavaMethod method = JavaElementFactory.newMethod(modifiers | Modifier.ABSTRACT,
type,
methodName,
null,
override
);
addMethod(method);
return method;
}
public JavaMethod addOverrideGetterMethod(String id,
int modifiers,
String type,
boolean override) {
String capitalizedName = StringUtils.capitalize(id);
String methodName = "get" + capitalizedName;
String bodyCode;
if (override) {
bodyCode = "super." + methodName + "()";
} else {
bodyCode = id;
}
bodyCode = "(" + type + ") " + bodyCode;
String content = String.format(GETTER_PATTERN, bodyCode);
JavaMethod method = JavaElementFactory.newMethod(modifiers,
type,
methodName,
content,
override
);
addMethod(method);
return method;
}
public void addField(JavaField field, boolean javaBean) {
addSimpleField(field);
String id = field.getName();
String capitalizedName = StringUtils.capitalize(id);
// add accessor method
int modifiers = Modifier.isProtected(field.getModifiers()) ?
Modifier.PUBLIC : Modifier.PROTECTED;
addGetterMethod(id,
modifiers,
field.getType(),
field.isOverride(),
false
);
if (javaBean) {
// add full javabean support accessor + mutator + constant with
// name of property to make it easier to use
// compute the property constant
String constantId = TypeManager.convertVariableNameToConstantName(
"property" + capitalizedName);
addSimpleField(JavaElementFactory.newField(
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL,
JAXXCompilerFinalizer.TYPE_STRING,
constantId, false, "\"" + id + "\"")
);
if (Boolean.class.getSimpleName().equals(field.getType())) {
String content = String.format(BOOLEAN_GETTER_PATTERN, id);
JavaMethod method = JavaElementFactory.newMethod(
Modifier.PUBLIC,
field.getType(),
"is" + capitalizedName,
content,
field.isOverride()
);
addMethod(method);
}
String content = String.format(SETTER_PATTERN,
field.getType(),
id,
constantId
);
JavaArgument arg = JavaElementFactory.newArgument(field.getType(),
id);
JavaMethod method = JavaElementFactory.newMethod(
Modifier.PUBLIC,
JAXXCompilerFinalizer.TYPE_VOID,
"set" + capitalizedName,
content,
field.isOverride(),
arg);
addMethod(method);
}
}
public void addSimpleField(JavaField field) {
if (log.isDebugEnabled()) {
log.debug("[" + getName() + "] Add field " + field.getName());
}
String fieldType = field.getType();
try {
String type = importManager.getType(fieldType);
field.setType(type);
} catch (Exception e) {
log.error("Could not determine simple name of field [" +
field.getName() + "] type " + fieldType);
}
if (field.hasInitializerTypes()) {
String code = simplifyCode(field.getInitializer(),
field.getInitializerTypes());
if (log.isDebugEnabled()) {
log.debug("Use simplify text : " + code);
}
field.setInitializer(code);
}
fields.add(field);
}
public void setSuperclassIsJAXXObject(boolean superclassIsJAXXObject) {
this.superclassIsJAXXObject = superclassIsJAXXObject;
}
public void setAbstractClass(boolean abstractClass) {
this.abstractClass = abstractClass;
}
public void setSuperGenericType(String superGenericType) {
this.superGenericType = superGenericType;
}
public void addBodyCode(String bodyCode) {
rawBodyCode.append(bodyCode);
}
/**
* Try to use a simple type fro the given {@code type} and apply it on the
* given {@code pattern}.
*
* Example :
*
* type = java.io.File, pattern = new %s("");
* returns : new File("") or new java.io.File("") if importManager can
* not import java.io.File
*
*
* @param types the types to simplify
* @param pattern the pattern where to apply simple types
* @return the input pattern with most simplest types
* @since 2.4
*/
public String simplifyCode(String pattern,
String... types) {
String[] simpleTypes = new String[types.length];
for (int i = 0; i < types.length; i++) {
String type = types[i];
String simpleType = importManager.getType(type);
simpleTypes[i] = simpleType;
}
return String.format(pattern, (Object[]) simpleTypes);
}
public void clear() {
importManager.clearImports();
if (interfaces != null) {
interfaces.clear();
interfaces = null;
}
if (methods != null) {
methods.clear();
methods = null;
}
if (constructors != null) {
constructors.clear();
constructors = null;
}
if (fields != null) {
fields.clear();
fields = null;
}
if (imports != null) {
imports.clear();
}
}
public List getConstructors() {
return constructors;
}
public void setSimpleName(String simpleName) {
this.simpleName = simpleName;
}
}