org.nuiton.eugene.java.JavaGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eugene Show documentation
Show all versions of eugene Show documentation
Efficient Universal Generator.
/*
* #%L
* EUGene :: EUGene
* %%
* Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
* %%
* 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.eugene.java;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.java.extension.AnnotationsManagerExtension;
import org.nuiton.eugene.java.extension.ImportsManagerExtension;
import org.nuiton.eugene.java.extension.ObjectModelAnnotation;
import org.nuiton.eugene.java.extension.ObjectModelAnnotationParameter;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelClassifier;
import org.nuiton.eugene.models.object.ObjectModelElement;
import org.nuiton.eugene.models.object.ObjectModelEnumeration;
import org.nuiton.eugene.models.object.ObjectModelGenerator;
import org.nuiton.eugene.models.object.ObjectModelInterface;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelParameter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* JavaGenerator
*
* Stupid generation of an ObjectModel with Java classes and interfaces.
* Use of ImportsManager to get imports for a classifier (added in model in the JavaBuilder which construct
* the ObjectModel).
*
* The JavaGenerator is based on a ObjectModelGenerator : Java classes are represented by ObjectModelClass, ...
* Created: 22 oct. 200
* 9
*
* @author Florian Desbois - [email protected]
* @plexus.component role="org.nuiton.eugene.Template" role-hint="org.nuiton.eugene.java.JavaGenerator"
*/
public class JavaGenerator extends ObjectModelGenerator {
private static final Log log = LogFactory.getLog(JavaGenerator.class);
protected int innerLevel;
protected String prefix;
@Override
public String getFilenameForClass(ObjectModelClass clazz) {
return getFilenameForClassifier(clazz);
}
@Override
public String getFilenameForInterface(ObjectModelInterface interfacez) {
return getFilenameForClassifier(interfacez);
}
@Override
public String getFilenameForEnumeration(ObjectModelEnumeration enumeration) {
return getFilenameForClassifier(enumeration);
}
@Override
public String getFilenameForClassifier(ObjectModelClassifier clazz) {
String s = clazz.getQualifiedName();
int index = s.indexOf("<");
if (index > -1) {
s = s.substring(0, index);
}
return s.replace('.', File.separatorChar) + ".java";
}
/**
* Generate from all classes.
*
* @param output Writer for generating the java file
* @param input Class to manage for creating an output file
* @throws IOException if any pb while writing file
*/
@Override
public void generateFromClass(Writer output, ObjectModelClass input)
throws IOException {
if (isVerbose()) {
log.info("Will generate class " + input.getQualifiedName());
}
preparePrefix(input);
// Imports, package et documentation
generateHeader(output, input);
String abstractStr = input.isAbstract() ? " abstract" : "";
String staticStr = input.isStatic() ? " static" : "";
String className = input.getName();
String extend = "";
Iterator j = input.getSuperclasses().iterator();
if (j.hasNext()) {
ObjectModelClassifier p = j.next();
extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
}
String implement = "";
for (Iterator i =
input.getInterfaces().iterator(); i.hasNext(); ) {
ObjectModelClassifier parentInterface = i.next();
String interfaceName = GeneratorUtil.getSimpleName(
parentInterface.getQualifiedName());
implement += interfaceName;
if (i.hasNext()) {
implement += ", ";
}
}
if (log.isDebugEnabled()) {
log.debug(className + " : super : " + extend + ", interfaces : "
+ implement);
}
generateAnnotations(output, input, input);
output.write(""+prefix+"public"+staticStr+""+abstractStr+" class "+className+"");
/*
* Définition de la super classe : il ne doit y avoir qu'une
*/
if (extend.length() > 0) {
output.write(" extends "+extend+"");
}
if (implement.length() > 0) {
output.write(" implements "+implement+"");
}
output.write(" {\n");
output.write("");
generateInnerClassifiers(output, input.getInnerClassifiers());
preparePrefix(input);
generateAttributes(output, input, input.getAttributes());
generateOperations(output, input, input.getOperations());
output.write(""+prefix+"} //"+className+"\n");
output.write("");
}
@Override
public void generateFromInterface(Writer output,
ObjectModelInterface input)
throws IOException {
if (isVerbose()) {
log.info("Will generate interface " + input.getQualifiedName());
}
preparePrefix(input);
// Imports, package et documentation
generateHeader(output, input);
String interfaceName = input.getName();
String extend = "";
Iterator j = input.getInterfaces().iterator();
while (j.hasNext()) {
ObjectModelClassifier p = j.next();
extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
if (j.hasNext()) {
extend += ", ";
}
}
generateAnnotations(output, input, input);
output.write(""+prefix+"public interface "+interfaceName+"");
/*
* Définition de la super interface : il peut y en avoir autant qu'on veut
*/
if (extend.length() > 0) {
output.write(" extends "+extend+"");
}
output.write(" {\n");
output.write("");
generateAttributes(output, input, input.getAttributes());
generateOperations(output, input, input.getOperations());
output.write(""+prefix+"} //"+interfaceName+"\n");
output.write("");
}
public void generateAnnotations(Writer output,
ObjectModelClassifier clazz,
ObjectModelElement element)
throws IOException {
AnnotationsManagerExtension managers = getModel().getExtension(
AnnotationsManagerExtension.OBJECTMODEL_EXTENSION,
AnnotationsManagerExtension.class);
List annotations =
managers.getAnnotations(clazz, element);
for (ObjectModelAnnotation annotation : annotations) {
// if (!annotation.trim().startsWith("@")) {
// // add @ prefix
// annotation = "@" + annotation.trim();
// }
StringBuilder annotationBuilder = new StringBuilder("@" + annotation.getType());
List annotationParameters = annotation.getParameters();
if (CollectionUtils.isNotEmpty(annotationParameters)) {
annotationBuilder.append('(');
List params = Lists.newArrayList();
for (ObjectModelAnnotationParameter annotationParameter : annotationParameters) {
String paramStr = annotationParameter.getName() + " = ";
Object value = annotationParameter.getValue();
if (value instanceof String) {
paramStr += "\"" + value + "\"";
} else if (value instanceof Enum) {
Enum anEnum = (Enum) value;
paramStr += anEnum.getClass().getSimpleName() + "." + value;
} else {
paramStr += value.toString();
}
params.add(paramStr);
}
Joiner.on(", ").appendTo(annotationBuilder, params);
annotationBuilder.append(')');
}
String annotationStr = annotationBuilder.toString();
if (element instanceof ObjectModelOperation || element instanceof ObjectModelAttribute) {
output.write(""+prefix+"");
annotationStr = " " + annotationStr;
}
output.write(""+annotationStr+"");
if (element instanceof ObjectModelClassifier || element instanceof ObjectModelOperation || element instanceof ObjectModelAttribute) {
output.write("\n");
output.write("");
}
}
}
@Override
public void generateFromEnumeration(Writer output,
ObjectModelEnumeration input) throws IOException {
//FIXME tchemit 20100718 I don't understand why having two methods FromEnum and FromEnumeration ?
generateFromEnum(output, input);
}
@Override
public void generateFromEnum(Writer output, ObjectModelEnumeration input)
throws IOException {
if (isVerbose()) {
log.info("Will generate enumeration " + input.getQualifiedName());
}
preparePrefix(input);
generateHeader(output, input); // Imports, package et documentation
String enumzName = input.getName();
String extend = "";
Iterator j = input.getInterfaces().iterator();
if (j.hasNext()) {
ObjectModelClassifier p = j.next();
extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
}
generateAnnotations(output, input, input);
output.write("\n");
output.write(""+prefix+"public enum "+enumzName+"");
if (extend.length() > 0) {
output.write(" implements "+extend+" {\n");
output.write("");
} else {
output.write(" {\n");
output.write("");
}
// generation of literal
if (input.getLiterals().isEmpty()) {
output.write(" ; ");
} else {
Iterator i = input.getLiterals().iterator();
while (i.hasNext()) {
String literal = i.next();
output.write(""+prefix+" "+literal+""+(i.hasNext() ? "," : ";")+"\n");
output.write("");
}
}
generateAttributes(output, input, input.getAttributes());
generateOperations(output, input, input.getOperations());
output.write(""+prefix+"} //"+enumzName+"\n");
output.write("");
}
public void generateInnerClassifiers(Writer output,
Collection
innerClassifiers)
throws IOException {
if (innerClassifiers == null || innerClassifiers.isEmpty()) {
return;
}
for (ObjectModelClassifier innerClassifier : innerClassifiers) {
if (innerClassifier.isClass()) {
generateFromClass(output, (ObjectModelClass) innerClassifier);
innerLevel--;
continue;
}
if (innerClassifier.isInterface()) {
generateFromInterface(output, (ObjectModelInterface)
innerClassifier);
innerLevel--;
continue;
}
if (innerClassifier.isEnum()) {
generateFromEnum(output, (ObjectModelEnumeration)
innerClassifier);
innerLevel--;
}
}
}
protected void preparePrefix(ObjectModelClassifier clazz) {
if (!clazz.isInner()) {
innerLevel = 0;
prefix = "";
} else {
innerLevel++;
char[] tmp = new char[innerLevel * 4];
Arrays.fill(tmp, ' ');
prefix = new String(tmp);
}
if (log.isDebugEnabled()) {
log.debug("prefix to use for classifier " +
clazz.getName() + " : [" + prefix + "]");
}
}
/**
* Generate Header for a classifier : Package, Documentation, Imports and Classifier signature.
*
* @param output Writer for generating the java file
* @param classifier Classifier for generate header
* @throws IOException if any pb while writing file
*/
protected void generateHeader(Writer output,
ObjectModelClassifier classifier)
throws IOException {
if (classifier.isInner()) {
return;
}
String packageName = classifier.getPackageName();
output.write("package "+packageName+";\n");
output.write("\n");
output.write("");
// potentiel crash si imports non defini -> IllegalArgumentException on "imports"
ImportsManagerExtension managers = getModel().getExtension(
ImportsManagerExtension.OBJECTMODEL_EXTENSION,
ImportsManagerExtension.class);
List imports = managers.getImports(classifier);
for (String singleImport : imports) {
output.write("import "+singleImport+";\n");
output.write("");
}
if (CollectionUtils.isNotEmpty(imports)) {
output.write("\n");
output.write("");
}
}
/**
* Generate attributes from a collection of ObjectModelAttribute.
*
* @param output Writer for generating the java file
* @param clazz classifier in generation
* @param attributes Collection of ObjectModelAttribute to generate
* @throws IOException if any pb while writing file
*/
protected void generateAttributes(Writer output, ObjectModelClassifier clazz,
Collection
attributes)
throws IOException {
for (ObjectModelAttribute attr : attributes) {
output.write("\n");
output.write("");
String documentation = attr.getDocumentation();
if (StringUtils.isNotEmpty(documentation)) {
output.write(""+prefix+" /**\n");
output.write("");
String[] lines = documentation.split("\n");
for (String line : lines) {
output.write(""+prefix+" * "+line+"\n");
output.write("");
}
output.write(""+prefix+" */\n");
output.write("");
}
generateAnnotations(output, clazz, attr);
String attrName = attr.getName();
String attrVisibility = attr.getVisibility();
String attrType = GeneratorUtil.getSimpleName(attr.getType());
String attrStatic = attr.isStatic() ? "static " : "";
String attrFinal = attr.isFinal() ? "final " : "";
String attrTransient = attr.isTransient() ? "transient " : "";
if (clazz instanceof ObjectModelInterface) {
//tchemit 20100507 no modifier for constants in interfaces
attrStatic = "";
attrFinal = "";
attrTransient = "";
attrVisibility = "";
}
if (StringUtils.isNotEmpty(attrVisibility)) {
attrVisibility += " ";
}
String attrValue = StringUtils.isNotEmpty(attr.getDefaultValue()) ?
// ANO#474 FD-20100408 : Don't do any simplification for
// defaultValue, must be managed when the attribute is added
// to the class in the Transformer.
" = " + attr.getDefaultValue() : "";
// " = " + GeneratorUtil.getSimpleName(attr.getDefaultValue()) : "";
output.write(""+prefix+" "+attrVisibility+""+attrStatic+""+attrFinal+""+attrTransient+""+attrType+" "+attrName+""+attrValue+";\n");
output.write("");
}
}
/**
* Generate operations from a collection of ObjectModelOperation
*
* @param output Writer for generating the java file
* @param clazz classifier in generation
* @param operations Collection of ObjectModelOperation to generate
* @throws IOException if any pb while writing file
*/
protected void generateOperations(Writer output, ObjectModelClassifier clazz,
Collection
operations) throws IOException {
if (!operations.isEmpty()) {
output.write("\n");
output.write("");
}
// Ano #493 : FD-20100412
// Use a boolean to know if the classifier is an interface
// Used to avoid generating visibility not needed for interface
boolean interfacez =
ObjectModelInterface.class.isAssignableFrom(clazz.getClass());
for (ObjectModelOperation op : operations) {
String opName = op.getName();
if (opName == null) {
generateBlock(output, clazz, op);
continue;
}
generateOperationDocumentation(output, op);
generateAnnotations(output, clazz, op);
String opVisibility = !interfacez ? op.getVisibility() : "";
String opStatic = op.isStatic() ? "static " : "";
String opAbstract = op.isAbstract() ? "abstract " : "";
ObjectModelParameter returnParam = op.getReturnParameter();
String opReturn = "";
if (returnParam != null) {
opReturn = GeneratorUtil.getSimpleName(
returnParam.getType()) + " ";
}
if (StringUtils.isNotEmpty(opVisibility)) {
opVisibility += " ";
}
output.write(""+prefix+" "+opVisibility+""+opStatic+""+opAbstract+""+opReturn+""+opName+"(");
String comma = "";
Collection params = op.getParameters();
for (ObjectModelParameter param : params) {
String paramName = param.getName();
String paramType = GeneratorUtil.getSimpleName(param.getType());
output.write(""+comma+""+paramType+" "+paramName+"");
comma = ", ";
}
output.write(")");
comma = " throws ";
Set exceptions = op.getExceptions();
for (String exception : exceptions) {
String exceptionName = GeneratorUtil.getSimpleName(exception);
output.write(""+comma+""+exceptionName+"");
comma = ", ";
}
// tchemit 2010-08-14 fix http://www.nuiton.org/issues/show/809
// if (!op.getBodyCode().isEmpty()) {
if (!(clazz instanceof ObjectModelInterface) && !op.isAbstract()) {
String body = op.getBodyCode() == null ? "" : op.getBodyCode();
output.write(""+prefix+" {"+body+""+prefix+"}\n");
output.write("\n");
output.write("");
} else {
output.write(";\n");
output.write("\n");
output.write("");
}
}
}
protected void generateOperationDocumentation(Writer output,
ObjectModelOperation op) throws IOException {
String documentation = op.getDocumentation();
if (StringUtils.isEmpty(documentation)) {
// no documentation for this operation
return;
}
output.write(""+prefix+" /**\n");
output.write(""+prefix+"");
String[] documentationLines = documentation.split("\n");
for (String documentationLine : documentationLines) {
output.write(""+prefix+" * "+documentationLine+"\n");
output.write("");
}
Collection params = op.getParameters();
for (ObjectModelParameter param : params) {
String paramName = param.getName();
String paramDocumentation = param.getDocumentation();
if (paramDocumentation == null) {
paramDocumentation = "";
}
output.write(""+prefix+" * @param "+paramName+" "+paramDocumentation+"\n");
output.write("");
}
ObjectModelParameter returnParam = op.getReturnParameter();
String opReturn = "";
if (returnParam != null) {
opReturn = GeneratorUtil.getSimpleName(
returnParam.getType()) + " ";
if (!opReturn.contains("void")) {
String paramDocumentation = returnParam.getDocumentation();
if (paramDocumentation == null) {
paramDocumentation = "";
}
output.write(""+prefix+" * @return "+paramDocumentation+"\n");
output.write("");
}
}
Set exceptions = op.getExceptions();
for (String exception : exceptions) {
String exceptionName = GeneratorUtil.getSimpleName(exception);
output.write(""+prefix+" * @throws "+exceptionName+"\n");
output.write("");
}
output.write(""+prefix+" */\n");
output.write("");
}
protected void generateBlock(Writer output,
ObjectModelClassifier clazz,
ObjectModelOperation op) throws IOException {
String opStatic = op.isStatic() ? "static " : " ";
output.write(""+prefix+" "+opStatic+"{\n");
output.write(""+prefix+" "+op.getBodyCode()+"\n");
output.write(""+prefix+" }\n");
output.write("\n");
output.write("");
}
}