org.faktorips.codegen.JavaCodeFragmentBuilder Maven / Gradle / Ivy
Show all versions of faktorips-dtfl-common Show documentation
/*******************************************************************************
* Copyright (c) Faktor Zehn GmbH - faktorzehn.org
*
* This source code is available under the terms of the AGPL Affero General Public License version
* 3.
*
* Please see LICENSE.txt for full license terms, including the additional permissions and
* restrictions as well as the possibility of alternative license terms.
*******************************************************************************/
package org.faktorips.codegen;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Objects;
import org.faktorips.runtime.internal.IpsStringUtils;
/**
* A builder to create JavaCodeFragments with a uniform coding style.
*
* JavaCodeFragmentBuilder uses the method chaining pattern: Every method modifying the
* {@link JavaCodeFragment} returns this JavaCodeFragmentBuilder so you could chain the methods as
* follows:
* {@code javaCodeFragmentBuilder.methodBegin().appendLn().methodEnd();}.
*/
public class JavaCodeFragmentBuilder {
// the fragment under construction
private JavaCodeFragment fragment;
// The modifier that was passed in the last methodBegin called.
private int lastMethodModifier;
/**
* Creates a new fragment builder to build Java source code.
*/
public JavaCodeFragmentBuilder() {
this(false);
}
/**
* Creates a new fragment builder to build Java source code.
*/
public JavaCodeFragmentBuilder(boolean indent) {
fragment = new JavaCodeFragment(indent);
}
/**
* Returns the fragment under construction.
*/
public JavaCodeFragment getFragment() {
return fragment;
}
/**
* Adds an import entry to the code fragment under construction.
*
* @param qualifiedClassName the java class that is added to the import declaration
*/
public JavaCodeFragmentBuilder addImport(String qualifiedClassName) {
fragment.addImport(qualifiedClassName);
return this;
}
/**
* Adds an import entry to the code fragment under construction.
*/
public JavaCodeFragmentBuilder addImport(Class> clazz) {
fragment.addImport(clazz.getName());
return this;
}
/**
* Appends a line separator to fragment's source code.
*/
public JavaCodeFragmentBuilder appendln() {
fragment.appendln();
return this;
}
/**
* Appends the given String to the fragment's source code.
*/
public JavaCodeFragmentBuilder append(String s) {
fragment.append(s);
return this;
}
/**
* Encloses the given String with double quotes (") and appends it to fragment.
*/
public JavaCodeFragmentBuilder appendQuoted(String s) {
fragment.appendQuoted(s);
return this;
}
/**
* Appends the given char to the fragment's source code.
*/
public JavaCodeFragmentBuilder append(char c) {
fragment.append(c);
return this;
}
/**
* Appends the given int to the fragment's source code.
*/
public JavaCodeFragmentBuilder append(int i) {
fragment.append(i);
return this;
}
/**
* Appends the class' unqualified name to the source code and updates the import declaration (if
* necessary).
*/
public JavaCodeFragmentBuilder appendClassName(Class> clazz) {
fragment.appendClassName(clazz);
return this;
}
/**
* Appends the unqualified class name to the source code and updates the import declaration (if
* necessary).
*/
public JavaCodeFragmentBuilder appendClassName(String qualifiedClassName) {
fragment.appendClassName(qualifiedClassName);
return this;
}
/**
* Appends the given String and a line separator to the fragment's source code.
*/
public JavaCodeFragmentBuilder appendln(String s) {
fragment.appendln(s);
return this;
}
/**
* Appends the given char to the fragment's source code.
*/
public JavaCodeFragmentBuilder appendln(char c) {
fragment.appendln(c);
return this;
}
/**
* Appends the given fragment to the fragment under construction and indents it properly.
*/
public JavaCodeFragmentBuilder append(JavaCodeFragment fragment) {
this.fragment.append(fragment);
return this;
}
/**
* Append the Java modifier translated to a String, e.g. for java.lang.reflect.Modifier.PUBLIC
* "public" is appended.
*
* @param modifier Modifier according to java.lang.reflect.Modifier
*
* @see java.lang.reflect.Modifier
*/
public JavaCodeFragmentBuilder appendJavaModifier(int modifier) {
append(Modifier.toString(modifier));
return this;
}
/**
* Adds an opening bracket followed by a newline and increases the indentation level by one
* afterwards.
*/
public JavaCodeFragmentBuilder openBracket() {
if (!fragment.bol()) {
fragment.appendln();
}
fragment.appendln('{');
fragment.incIndentationLevel();
return this;
}
/**
* Adds a closing bracket and decreases the indentation level by one afterwards.
*/
public JavaCodeFragmentBuilder closeBracket() {
fragment.decIndentationLevel();
if (!fragment.bol()) {
fragment.appendln();
}
fragment.appendln('}');
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
*/
public JavaCodeFragmentBuilder method(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
JavaCodeFragment body,
String javadoc) {
javaDoc(javadoc);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType The className that the methods returns an instance of or null
* to indicate no return type in case of a constructor. The return type
* void
is indicated by java.lang.Void.class
:
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass) {
methodBegin(modifier, returnType, methodName, argName, argClass, null);
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType The className that the methods returns an instance of or null
* to indicate no return type in case of a constructor. The return type
* void
is indicated by java.lang.Void.class
:
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
Class>[] exceptionClasses) {
signatureInternal(modifier, methodName, new ClassAsParameterTypeSupport(argName, argClass, exceptionClasses,
returnType), false);
if (!Modifier.isAbstract(modifier)) {
openBracket();
}
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
*/
public JavaCodeFragmentBuilder method(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
JavaCodeFragment body,
String javadoc) {
javaDoc(javadoc);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param exceptionClasses Exception classes that can be thrown by the generated method
* @param body the method body
* @param javadoc the java documentation
*/
// CSOFF: ParameterNumber
public JavaCodeFragmentBuilder method(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
Class>[] exceptionClasses,
JavaCodeFragment body,
String javadoc) {
// CSON: ParameterNumber
javaDoc(javadoc);
methodBegin(modifier, returnType, methodName, argName, argClass, exceptionClasses);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
* @param javaDocAnnotations annotations of the java documentation
*/
// CSOFF: ParameterNumber
public JavaCodeFragmentBuilder method(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
JavaCodeFragment body,
String javadoc,
String... javaDocAnnotations) {
// CSON: ParameterNumber
javaDoc(javadoc, javaDocAnnotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
* @param javaDocAnnotations annotations of the java documentation
* @param annotations Java 5 annotations
*/
// CSOFF: ParameterNumber
public JavaCodeFragmentBuilder method(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
JavaCodeFragment body,
String javadoc,
String[] javaDocAnnotations,
String[] annotations) {
// CSON: ParameterNumber
javaDoc(javadoc, javaDocAnnotations);
annotation(annotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
* @param javaDocAnnotations annotations of the java documentation
*/
// CSOFF: ParameterNumber
public JavaCodeFragmentBuilder method(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
JavaCodeFragment body,
String javadoc,
String... javaDocAnnotations) {
// CSON: ParameterNumber
javaDoc(javadoc, javaDocAnnotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method including signature, body and java doc.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor
* @param methodName the name of the method.
* @param argName Argument names.
* @param argClass Argument classes.
* @param body the method body
* @param javadoc the java documentation
* @param javaDocAnnotations annotations of the java documentation
* @param annotations Java 5 annotations
*/
// CSOFF: ParameterNumber
public JavaCodeFragmentBuilder method(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
JavaCodeFragment body,
String javadoc,
String[] javaDocAnnotations,
String[] annotations) {
// CSON: ParameterNumber
javaDoc(javadoc, javaDocAnnotations);
annotation(annotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
append(body);
methodEnd();
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param javaDoc the java documentation for this method signature
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
String javaDoc) {
javaDoc(javaDoc);
methodBegin(modifier, returnType, methodName, argName, argClass);
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param javaDoc the java documentation for this method signature
* @param javaDocAnnotations annotations of the java documentation
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
String javaDoc,
String[] javaDocAnnotations) {
javaDoc(javaDoc, javaDocAnnotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param javaDoc the java documentation for this method signature
* @param javaDocAnnotations annotations of the java documentation
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
Class> returnType,
String methodName,
String[] argName,
Class>[] argClass,
String javaDoc,
String[] javaDocAnnotations) {
javaDoc(javaDoc, javaDocAnnotations);
methodBegin(modifier, returnType, methodName, argName, argClass);
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass) {
signature(modifier, returnType, methodName, argName, argClass);
if (!Modifier.isAbstract(modifier)) {
openBracket();
}
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder methodBegin(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
String[] exceptionClasses) {
signature(modifier, returnType, methodName, argName, argClass, exceptionClasses);
if (!Modifier.isAbstract(modifier)) {
openBracket();
}
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder signature(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass) {
signature(modifier, returnType, methodName, argName, argClass, false);
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
*/
public JavaCodeFragmentBuilder signature(int modifier,
JavaCodeFragment returnType,
String methodName,
String[] argName,
String[] argClass) {
signatureInternal(modifier, methodName, new StringAsParameterTypeSupport(argName, argClass, null, returnType),
false);
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param argFinal indicates if the arguments are prefix be a final modifier
*/
public JavaCodeFragmentBuilder signature(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
boolean argFinal) {
JavaCodeFragment returnCode = null;
if (returnType != null) {
returnCode = new JavaCodeFragment();
returnCode.appendClassName(returnType);
}
signatureInternal(modifier, methodName, new StringAsParameterTypeSupport(argName, argClass, null, returnCode),
argFinal);
return this;
}
private JavaCodeFragmentBuilder signatureInternal(int modifier,
String methodName,
MethodSignatureTypesSupport support,
boolean argFinal) {
lastMethodModifier = modifier;
append(Modifier.toString(modifier));
append(' ');
if (support.hasReturnType()) {
support.appendReturnType();
append(' ');
}
append(methodName);
append('(');
for (int i = 0; i < support.getNumberOfParameters(); i++) {
if (i > 0) {
append(", "); //$NON-NLS-1$
}
if (argFinal) {
append("final "); //$NON-NLS-1$
}
support.appendParameterType(i);
append(' ');
support.appendParameterName(i);
}
append(')');
if (support.getNumberOfExceptionExtensions() == 0) {
return this;
}
append(" throws "); //$NON-NLS-1$
for (int i = 0, max = support.getNumberOfExceptionExtensions(); i < max; i++) {
if (i > 0) {
append(", "); //$NON-NLS-1$
}
support.appendExceptionExtension(i);
}
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param exceptionClasses the thrown exceptions
*/
public JavaCodeFragmentBuilder signature(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
String[] exceptionClasses) {
JavaCodeFragment returnCode = null;
if (returnType != null) {
returnCode = new JavaCodeFragment();
returnCode.appendClassName(returnType);
}
signatureInternal(modifier, methodName, new StringAsParameterTypeSupport(argName, argClass, exceptionClasses,
returnCode), false);
return this;
}
/**
* Creates the Java source code for a method signature.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param exceptionClasses the thrown exceptions
*/
public JavaCodeFragmentBuilder signature(int modifier,
JavaCodeFragment returnType,
String methodName,
String[] argName,
String[] argClass,
String[] exceptionClasses) {
signatureInternal(modifier, methodName, new StringAsParameterTypeSupport(argName, argClass, exceptionClasses,
returnType), false);
return this;
}
/**
* Creates the Java source code for a method signature. If the method is non abstract the
* generated code ends with an opening bracket '{'. If the method is abstract the code ends with
* the argument list's closing bracket ')'.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param returnType the className that the methods returns an instance of or null to indicate
* no return type in case of a constructor.
* @param argName Argument names.
* @param argClass Argument classes.
* @param javaDoc the java documentation for this method signature
* @param javaDocAnnotations annotations of the java documentation
*/
public JavaCodeFragmentBuilder signature(int modifier,
String returnType,
String methodName,
String[] argName,
String[] argClass,
String javaDoc,
String[] javaDocAnnotations) {
javaDoc(javaDoc, javaDocAnnotations);
signature(modifier, returnType, methodName, argName, argClass);
return this;
}
/**
* Appends the source code for the the end of a method. If the method is abstract a semicolon is
* generated, otherwise a closing bracket. If the method is abstract or not, is determined from
* the modifier used in the last call to methodBegin().
*/
public JavaCodeFragmentBuilder methodEnd() {
if (Modifier.isAbstract(lastMethodModifier)) {
fragment.appendln(";"); //$NON-NLS-1$
} else {
closeBracket();
}
fragment.appendln();
return this;
}
/**
* Appends the source code for the beginning of a new class at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder classBegin(int modifier, String className) {
classBegin(modifier, className, (String)null, null);
return this;
}
/**
* Appends the source code for the beginning of a new class at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder classBegin(int modifier,
String className,
Class> extendsClass,
Class>[] interfaces) {
String extendsClassString = extendsClass == null ? null : extendsClass.getName();
if (interfaces == null) {
classBegin(modifier, className, extendsClassString, null);
return this;
}
String[] interfaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
interfaceNames[i] = interfaces[i].getName();
}
classBegin(modifier, className, extendsClassString, interfaceNames);
return this;
}
/**
* Appends the source code for the beginning of a new class at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder classBegin(int modifier,
String className,
String extendsClassName,
String[] interfaces) {
fragment.append(Modifier.toString(modifier));
fragment.append(" class "); //$NON-NLS-1$
fragment.append(className);
if (extendsClassName != null) {
fragment.append(" extends "); //$NON-NLS-1$
fragment.appendClassName(extendsClassName);
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (i == 0) {
fragment.append(" implements "); //$NON-NLS-1$
} else {
fragment.append(", "); //$NON-NLS-1$
}
fragment.appendClassName(interfaces[i]);
}
}
fragment.appendln();
openBracket();
fragment.appendln();
return this;
}
/**
* Appends the source code for the beginning of a new enum at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder enumBegin(int modifier,
String className,
String extendsClassName,
String[] interfaces) {
fragment.append(Modifier.toString(modifier));
fragment.append(" enum "); //$NON-NLS-1$
fragment.append(className);
if (extendsClassName != null) {
fragment.append(" extends "); //$NON-NLS-1$
fragment.appendClassName(extendsClassName);
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (i == 0) {
fragment.append(" implements "); //$NON-NLS-1$
} else {
fragment.append(", "); //$NON-NLS-1$
}
fragment.appendClassName(interfaces[i]);
}
}
fragment.appendln();
openBracket();
fragment.appendln();
return this;
}
/**
* Writes the code at the end of a class.
*/
public JavaCodeFragmentBuilder classEnd() {
closeBracket();
return this;
}
/**
* Appends the source code for the beginning of a new interface at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder interfaceBegin(String interfaceName) {
interfaceBegin(interfaceName, ""); //$NON-NLS-1$
return this;
}
/**
* Appends the source code for the beginning of a new interface at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder interfaceBegin(String interfaceName, String extendsInterfaceName) {
fragment.append("public interface "); //$NON-NLS-1$
fragment.append(interfaceName);
if (IpsStringUtils.isNotEmpty(extendsInterfaceName)) {
fragment.append(" extends "); //$NON-NLS-1$
fragment.appendClassName(extendsInterfaceName);
}
fragment.appendln();
openBracket();
return this;
}
/**
* Appends the source code for the beginning of a new interface at the end of the fragment under
* construction.
*/
public JavaCodeFragmentBuilder interfaceBegin(String interfaceName, String[] extendedInterfaces) {
fragment.append("public interface "); //$NON-NLS-1$
fragment.append(interfaceName);
if (extendedInterfaces != null && extendedInterfaces.length > 0) {
fragment.append(" extends "); //$NON-NLS-1$
for (int i = 0; i < extendedInterfaces.length; i++) {
if (i > 0) {
fragment.append(", "); //$NON-NLS-1$
}
fragment.appendClassName(extendedInterfaces[i]);
}
}
fragment.appendln();
openBracket();
return this;
}
/**
* Creates a new variable declaration.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param clazz The class the variable is an instance of
* @param varName the variable's name.
*/
public JavaCodeFragmentBuilder varDeclaration(int modifier, Class> clazz, String varName) {
varDeclaration(modifier, clazz.getName(), varName);
return this;
}
/**
* Creates a new variable declaration.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param clazz The class the variable is an instance of
* @param varName the variable's name.
* @param expression the initial value of the variable
*/
public JavaCodeFragmentBuilder varDeclaration(int modifier,
Class> clazz,
String varName,
JavaCodeFragment expression) {
varDeclaration(modifier, clazz.getName(), varName, expression);
return this;
}
/**
* Creates a new variable declaration.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param className The class' name the variable is an instance of
* @param varName the variable's name.
* @param expression the initial value of the variable
*/
public JavaCodeFragmentBuilder varDeclaration(int modifier,
String className,
String varName,
JavaCodeFragment expression) {
JavaCodeFragment code = new JavaCodeFragment();
code.appendClassName(className);
return varDeclaration(modifier, code, varName, expression);
}
/**
* Creates a new variable declaration.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param className The class' name the variable is an instance of
* @param varName the variable's name.
* @param expression the initial value of the variable
*/
public JavaCodeFragmentBuilder varDeclaration(int modifier,
JavaCodeFragment className,
String varName,
JavaCodeFragment expression) {
if (modifier > 0) {
fragment.append(Modifier.toString(modifier));
fragment.append(' ');
}
if (className != null) {
append(className);
append(' ');
}
fragment.append(varName);
if (expression != null) {
fragment.append(" = "); //$NON-NLS-1$
fragment.append(expression);
}
fragment.appendln(";"); //$NON-NLS-1$
return this;
}
/**
* Creates a new variable declaration.
*
* @param modifier Access modifier according to java.lang.reflect.Modifier.
* @param className The class' name the variable is an instance of
* @param varName the variable's name.
*/
public JavaCodeFragmentBuilder varDeclaration(int modifier, String className, String varName) {
varDeclaration(modifier, className, varName, null);
return this;
}
/**
* Writes a variable definition.
*/
public JavaCodeFragmentBuilder varDefinition(Class> varClass, String varName, String varValue) {
varDefinition(varClass.getName(), varName, varValue);
return this;
}
/**
* Writes a variable definition.
*/
public JavaCodeFragmentBuilder varDefinition(String classOrTypeName, String variableName, String variableValue) {
fragment.append(classOrTypeName);
fragment.append(' ');
assignment(variableName, variableValue);
return this;
}
/**
* Appends a new assignment.
*
*
* varName = value;
*
*/
public JavaCodeFragmentBuilder assignment(String variable, JavaCodeFragment expression) {
fragment.append(variable);
fragment.append(" = "); //$NON-NLS-1$
fragment.append(expression);
fragment.appendln(";"); //$NON-NLS-1$
return this;
}
/**
* Creates a new variable declaration.
*
*
* varName = value;
*
*/
public JavaCodeFragmentBuilder assignment(String variable, String value) {
fragment.append(variable);
fragment.append(" = "); //$NON-NLS-1$
fragment.append(value);
fragment.appendln(";"); //$NON-NLS-1$
return this;
}
public JavaCodeFragmentBuilder singleLineComment(String comment) {
fragment.append("// "); //$NON-NLS-1$
if (comment != null) {
fragment.appendln(comment);
}
return this;
}
public JavaCodeFragmentBuilder multiLineComment(String comment) {
fragment.appendln("/*"); //$NON-NLS-1$
if (comment != null) {
fragment.appendln(" "); //$NON-NLS-1$
fragment.appendln(comment);
}
fragment.appendln("*/"); //$NON-NLS-1$
return this;
}
/**
* Puts the given text and annotations into a java doc comment. For an annotation only the
* annotation name and optionally separated by a space character an annotation text needs to be
* specified. The '@' character will be automatically added.
*/
@SuppressWarnings("null")
public JavaCodeFragmentBuilder javaDoc(String text, String... annotations) {
if (text == null && annotations == null) {
return this;
}
fragment.appendln("/**"); //$NON-NLS-1$
if (IpsStringUtils.isNotEmpty(text)) {
text.lines().forEach(line -> {
fragment.append(" * "); //$NON-NLS-1$
fragment.appendln(line);
});
}
if (annotations != null) {
// create an empty line to separate the text (if any) from the custom tags.
if (IpsStringUtils.isNotEmpty(text)) {
fragment.appendln(" *"); //$NON-NLS-1$
}
for (String annotation : annotations) {
fragment.append(" * @"); //$NON-NLS-1$
fragment.appendln(annotation);
}
}
fragment.appendln(" */"); //$NON-NLS-1$
return this;
}
/**
* Writes each annotation with a line separator. Import statements are added automatically to
* the code fragment (if needed).
*/
public JavaCodeFragmentBuilder annotationLn(Class>... annotations) {
if (annotations == null) {
return this;
}
for (Class> annotation : annotations) {
fragment.append("@"); //$NON-NLS-1$
fragment.appendClassName(annotation);
fragment.appendln();
}
return this;
}
/**
* Writes the annotation with the indicated parameters and a line separator. '@' character and a
* line feed will be automatically added. Import statements are added automatically to the code
* fragment (if needed).
*
* @param annotation The annotation class
* @param params Parameters for the annotation without parenthesis. If null
or an
* empty String, parenthesis aren't added.
*/
public JavaCodeFragmentBuilder annotationLn(Class> annotation, String params) {
JavaCodeFragment paramsCodeFragment = new JavaCodeFragment();
if (IpsStringUtils.isNotEmpty(params)) {
paramsCodeFragment.append(params);
}
return annotationLn(annotation, paramsCodeFragment);
}
/**
* Writes the annotation with the indicated parameters and a line separator. '@' character and a
* line feed will be automatically added. Import statements are added automatically to the code
* fragment (if needed).
*
* @param annotation The annotation class
* @param params Parameters for the annotation without parenthesis. If empty, parenthesis aren't
* added.
*/
public JavaCodeFragmentBuilder annotationLn(Class> annotation, JavaCodeFragment params) {
annotation(annotation.getName(), params).appendln();
return this;
}
/**
* Writes the annotation with the indicated parameters and a line separator. '@' character and a
* line feed will be automatically added. Import statements are added automatically to the code
* fragment (if needed).
*
* @param annotation The annotation class
* @param params Parameters for the annotation without parenthesis. If empty, parenthesis aren't
* added.
*/
public JavaCodeFragmentBuilder annotation(Class> annotation, JavaCodeFragment params) {
if (annotation == null) {
return this;
}
annotation(annotation.getName(), params);
return this;
}
/**
* Writes the annotation with the indicated parameter of type String and adds a line separator.
* '@' character and a line feed will be automatically added. Import statements are added
* automatically to the code fragment (if needed).
*
*
* Example
* annotation : javax.xml.bind.annotation.XmlRootElement
* paramName : name
* stringValue: policy
* Result: @XmlElement(name="Policy")
*
*
* @param annotation The annotation class
* @param paramName The name of the parameter
* @param stringValue The unquoted string value for the parameter. This method generates the
* quotes.
*
*/
public JavaCodeFragmentBuilder annotationLn(Class> annotation, String paramName, String stringValue) {
if (annotation == null) {
return this;
}
annotationLn(annotation.getName(), paramName, stringValue);
return this;
}
/**
* Writes the annotation with the indicated parameters. '@' character and a line feed will be
* automatically added. Import statements are added automatically to the code fragment (if
* needed).
*
* @param annotation The annotation class
* @param params Parameters for the annotation without parenthesis. If null
or an
* empty String, parenthesis aren't added.
*/
public JavaCodeFragmentBuilder annotationLn(String annotation, JavaCodeFragment params) {
return annotation(annotation, params).appendln();
}
/**
* Writes the annotation with the indicated parameters. '@' character and a line feed will be
* automatically added. Import statements are added automatically to the code fragment (if
* needed).
*
* @param annotation The annotation class
* @param params Parameters for the annotation without parenthesis. If null
or an
* empty String, parenthesis aren't added.
*/
public JavaCodeFragmentBuilder annotation(String annotation, JavaCodeFragment params) {
if (annotation == null) {
return this;
}
fragment.append("@"); //$NON-NLS-1$
fragment.appendClassName(annotation);
if (params != null && params.getSourcecode().length() > 0) {
fragment.append('(');
fragment.append(params);
fragment.append(')');
}
return this;
}
public JavaCodeFragmentBuilder annotationLn(String annotation, String params) {
JavaCodeFragment paramsCodeFragment = new JavaCodeFragment();
if (IpsStringUtils.isNotEmpty(params)) {
paramsCodeFragment.append(params);
}
return annotationLn(annotation, paramsCodeFragment);
}
/**
* Writes the annotation with the indicated parameter of type String. '@' character and a line
* feed will be automatically added. Import statements are added automatically to the code
* fragment (if needed).
*
*
* Example
* annotation : javax.xml.bind.annotation.XmlRootElement
* paramName : name
* stringValue: policy
* Result: @XmlElement(name="policy")
*
*
* @param annotation The annotation class
* @param paramName The name of the parameter
* @param stringValue The unquoted string value for the parameter. This method generates the
* quotes.
*
*/
public JavaCodeFragmentBuilder annotationLn(String annotation, String paramName, String stringValue) {
if (annotation == null) {
return this;
}
annotation(annotation, paramName, stringValue);
fragment.appendln();
return this;
}
/**
* Writes the annotation with the indicated parameter of type String. '@' character will be
* automatically added. Import statements are added automatically to the code fragment (if
* needed).
*
*
* Example
* annotation : javax.xml.bind.annotation.XmlRootElement
* paramName : name
* stringValue: policy
* Result: @XmlElement(name="policy")
*
*
* @param annotation The annotation class
* @param paramName The name of the parameter
* @param stringValue The unquoted string value for the parameter. This method generates the
* quotes.
*
*/
public JavaCodeFragmentBuilder annotation(String annotation, String paramName, String stringValue) {
if (annotation == null) {
return this;
}
fragment.append("@"); //$NON-NLS-1$
fragment.appendClassName(annotation);
fragment.append('(');
fragment.append(paramName);
fragment.append('=');
fragment.appendQuoted(stringValue);
fragment.append(')');
return this;
}
/**
* Writes the annotation for a class value. '@' character and a line feed will be automatically
* added. Import statements are added automatically to the code fragment (if needed).
*
*
* Example
* annotation : javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
* paramName : value
* qualifiedClassName: EnumValueXmlAdapter
* Result: @XmlJavaTypeAdapter(value = EnumValueXmlAdapter.class)
*
*
* @param annotation The annotation class
* @param paramName The name of the parameter
* @param qualifiedClassName The class value for the parameter
*/
public JavaCodeFragmentBuilder annotationClassValueLn(String annotation,
String paramName,
String qualifiedClassName) {
if (annotation == null) {
return this;
}
fragment.append("@"); //$NON-NLS-1$
fragment.appendClassName(annotation);
fragment.append('(');
fragment.append(paramName);
fragment.append('=');
fragment.appendClassName(qualifiedClassName);
fragment.append(".class"); //$NON-NLS-1$
fragment.append(')');
fragment.appendln();
return this;
}
/**
* Writes the annotations. For an annotation only the annotation name needs to be specified. The
* '@' character and a line feed will be automatically added.
*/
public JavaCodeFragmentBuilder annotation(String[] annotations) {
if (annotations == null) {
return this;
}
for (String annotation : annotations) {
annotationLn(annotation);
}
return this;
}
/**
* Writes the annotation. For an annotation the (fully qualified) annotation class name needs to
* be specified. The '@' character and a line feed will be automatically added. The annotation
* may contain parameters in parenthesis.
*
* @param annotation The fully qualified annotation name with parameters
*/
public JavaCodeFragmentBuilder annotationLn(String annotation) {
if (annotation == null) {
return this;
}
fragment.append("@"); //$NON-NLS-1$
int index = annotation.indexOf('(');
if (index == -1) {
fragment.appendClassName(annotation);
fragment.appendln();
return this;
}
fragment.appendClassName(annotation.substring(0, index));
fragment.appendln(annotation.substring(index));
return this;
}
/**
* Writes a method call to the java code fragment builder.
*
* @param name The name of the method to call
* @param parameters the parameters for the method call
* @return the fragment builder for method chaining
*/
public JavaCodeFragmentBuilder methodCall(String name, String[] parameters, boolean finishLine) {
fragment.append(name);
appendParameters(parameters);
if (finishLine) {
fragment.appendln(';');
}
return this;
}
/**
* Writes a method call to the java code fragment builder.
*
* @param name The name of the method to call
* @param parameterFragments the parameters for the method call
* @return the fragment builder for method chaining
*/
public JavaCodeFragmentBuilder methodCall(String name, JavaCodeFragment[] parameterFragments, boolean finishLine) {
fragment.append(name);
appendParameters(parameterFragments);
if (finishLine) {
fragment.appendln(';');
}
return this;
}
/**
* @see #methodCall(String, String[], boolean)
*
* @param name the name of the method
* @param parameters the list of parameters
* @return the fragment builder for method chaining
*/
public JavaCodeFragmentBuilder methodCall(String name, List parameters, boolean finishLine) {
return methodCall(name, parameters.toArray(new String[parameters.size()]), finishLine);
}
/**
* append a constructor call: new <name>(parameters[0], parameters[1], ...)
*
* @param finishLine append a semicolon and new line if true
* @return the JavaCodeFragmentBuilder for Method chaining
*/
public JavaCodeFragmentBuilder constructorCall(String className, String[] parameters, boolean finishLine) {
append("new "); //$NON-NLS-1$
appendClassName(className);
appendParameters(parameters);
if (finishLine) {
fragment.appendln(';');
}
return this;
}
/**
* @return The created instance of {@link JavaCodeFragmentBuilder}
* @see #constructorCall(String, String[], boolean)
*/
public JavaCodeFragmentBuilder constructorCall(String className, List parameters, boolean finishLine) {
return constructorCall(className, parameters.toArray(new String[parameters.size()]), finishLine);
}
public JavaCodeFragmentBuilder appendParameters(String[] parameters) {
JavaCodeFragment[] jcfParams = new JavaCodeFragment[parameters.length];
for (int i = 0; i < parameters.length; i++) {
jcfParams[i] = new JavaCodeFragment(parameters[i]);
}
appendParameters(jcfParams);
return this;
}
public JavaCodeFragmentBuilder appendParameters(JavaCodeFragment[] parameters) {
append('(');
fragment.appendJoined(parameters);
append(')');
return this;
}
/**
* Appends the generic parameters to the builder: <className1, className2, ...>. An import
* statement is added if a given class has not yet been imported.
*
* Note: You have to make sure that generics are supported by target compiler
*/
public JavaCodeFragmentBuilder appendGenerics(String... classNames) {
if (classNames.length > 0) {
append('<');
for (String className : classNames) {
appendClassName(className);
if (!className.equals(classNames[classNames.length - 1])) {
append(", "); //$NON-NLS-1$
}
}
append('>');
}
return this;
}
/**
* Appends the generic parameters to the builder: <class1, class2, ...>. An import
* statement is added if a given class has not yet been imported.
*
* Note: You have to make sure that generics are supported by target compiler
*/
public JavaCodeFragmentBuilder appendGenerics(Class>... classes) {
if (classes.length > 0) {
append('<');
int i = 1;
for (Class> clazz : classes) {
appendClassName(clazz);
if (i < classes.length) {
append(", "); //$NON-NLS-1$
i++;
}
}
append('>');
}
return this;
}
public JavaCodeFragmentBuilder appendJoin(List parts, String separator) {
if (parts == null) {
return this;
}
String nullSafeSeparator = Objects.toString(separator, IpsStringUtils.EMPTY);
for (int i = 0; i < parts.size(); i++) {
append(parts.get(i));
if (i + 1 < parts.size()) {
append(nullSafeSeparator);
}
}
return this;
}
@Override
public String toString() {
return fragment.toString();
}
/**
* The method
methods of this builder accept java.lang.String
or
* java.lang.Class
values for defining the type of a parameter or the return type
* of a method. The slight variations on how to process the two different types a covered by
* implementations of this class.
*
* @author Peter Erzberger
*/
private abstract static class MethodSignatureTypesSupport {
protected void check(String[] parameterNames, Object[] parameterTypes) {
if (parameterNames != null && parameterNames.length != parameterTypes.length) {
throw new RuntimeException("Named and Class array must have the same length"); //$NON-NLS-1$
}
}
public abstract boolean hasReturnType();
public abstract void appendReturnType();
public abstract int getNumberOfParameters();
public abstract void appendParameterName(int index);
public abstract void appendParameterType(int index);
public abstract void appendExceptionExtension(int index);
public abstract int getNumberOfExceptionExtensions();
}
private class ClassAsParameterTypeSupport extends MethodSignatureTypesSupport {
private String[] parameterNames = null;
private Class>[] parameterTypes = null;
private Class> returnType = null;
private Class>[] exceptionClasses = null;
/**
*
*/
public ClassAsParameterTypeSupport(String[] parameterNames, Class>[] parameterTypes,
Class>[] exceptionClasses, Class> returnType) {
check(parameterNames, parameterTypes);
this.parameterNames = parameterNames;
this.parameterTypes = parameterTypes;
this.exceptionClasses = exceptionClasses;
this.returnType = returnType;
}
@Override
public void appendParameterName(int index) {
append(parameterNames[index]);
}
@Override
public void appendParameterType(int index) {
appendClassName(parameterTypes[index]);
}
@Override
public void appendReturnType() {
appendClassName(returnType);
}
@Override
public int getNumberOfParameters() {
return parameterNames == null ? 0 : parameterNames.length;
}
@Override
public boolean hasReturnType() {
return returnType != null;
}
@Override
public void appendExceptionExtension(int index) {
appendClassName(exceptionClasses[index]);
}
@Override
public int getNumberOfExceptionExtensions() {
return exceptionClasses == null ? 0 : exceptionClasses.length;
}
}
private class StringAsParameterTypeSupport extends MethodSignatureTypesSupport {
private String[] parameterNames = null;
private String[] parameterTypes = null;
private String[] exceptionClasses = null;
private JavaCodeFragment returnType = null;
/**
*
*/
public StringAsParameterTypeSupport(String[] parameterNames, String[] parameterTypes,
String[] exceptionClasses, JavaCodeFragment returnType) {
check(parameterNames, parameterTypes);
this.parameterNames = parameterNames;
this.parameterTypes = parameterTypes;
this.exceptionClasses = exceptionClasses;
this.returnType = returnType;
}
@Override
public void appendParameterName(int index) {
append(parameterNames[index]);
}
@Override
public void appendParameterType(int index) {
appendClassName(parameterTypes[index]);
}
@Override
public void appendReturnType() {
append(returnType);
}
@Override
public int getNumberOfParameters() {
return parameterNames == null ? 0 : parameterNames.length;
}
@Override
public boolean hasReturnType() {
return returnType != null;
}
@Override
public void appendExceptionExtension(int index) {
appendClassName(exceptionClasses[index]);
}
@Override
public int getNumberOfExceptionExtensions() {
return exceptionClasses == null ? 0 : exceptionClasses.length;
}
}
}