/*
* Copyright ( c ) 2018 , 2022 , Oracle and / or its affiliates . All rights reserved .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation .
*
* This code 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 Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
*/
package builder;
import toolbox.ToolBox;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Builder for type declarations .
* Note : this implementation does not support everything and is not
* exhaustive .
*/
public class ClassBuilder extends AbstractBuilder {
private final ToolBox tb;
private final String fqn;
private final String clsname;
private final String typeParameter;
private String pkg;
private final List<String> imports;
private String extendsType;
private final List<String> implementsTypes;
private final List<MemberBuilder> members;
private final List<ClassBuilder> inners;
private final List<ClassBuilder> nested;
final static Pattern CLASS_RE = Pattern.compile("(.*)(<.*>)" );
/**
* Creates a class builder .
* @ param tb the toolbox reference
* @ param name the name of the type
*/
public ClassBuilder(ToolBox tb, String name) {
super (new Modifiers(), name);
this .tb = tb;
Matcher m = CLASS_RE.matcher(name);
if (m.matches()) {
fqn = m.group(1 );
typeParameter = m.group(2 );
} else {
fqn = name;
typeParameter = null ;
}
if (fqn.contains("." )) {
this .pkg = name.substring(0 , fqn.lastIndexOf('.' ));
clsname = fqn.substring(fqn.lastIndexOf('.' ) + 1 );
} else {
clsname = fqn;
}
imports = new ArrayList<>();
implementsTypes = new ArrayList<>();
members = new ArrayList<>();
nested = new ArrayList<>();
inners = new ArrayList<>();
}
/**
* Adds an import ( s ) .
* @ param i the import type .
* @ return this builder .
*/
public ClassBuilder addImports(String i) {
imports.add(i);
return this ;
}
/**
* Sets the modifiers for this builder .
* @ param modifiers the modifiers
* @ return this builder
*/
public ClassBuilder setModifiers(String... modifiers) {
this .modifiers.setModifiers(modifiers);
return this ;
}
/**
* Sets the enclosing type ' s name .
*
* @ param className the enclosing type ' s name
*/
@Override
void setClassName(String className) {
cname = className;
}
/**
* Sets a comment for the element .
*
* @ param comments for the element
* @ return this builder .
*/
@Override
public ClassBuilder setComments(String... comments) {
super .setComments(comments);
return this ;
}
/**
* Sets a comment for the element . Typically used to set
* the user ' s preferences whether an automatic comment is
* required or no API comment .
*
* @ param kind of comment , automatic or no comment .
* @ return this builder .
*/
@Override
public ClassBuilder setComments(Comment.Kind kind) {
super .setComments(kind);
return this ;
}
/**
* Set the super - type of the type .
* @ param name of the super type .
* @ return this builder .
*/
public ClassBuilder setExtends(String name) {
extendsType = name;
return this ;
}
/**
* Adds an implements declaration ( s ) .
* @ param names the interfaces
* @ return this builder .
*/
public ClassBuilder addImplements(String... names) {
implementsTypes.addAll(List.of(names));
return this ;
}
/**
* Adds a member ( s ) to the class declaration .
* @ param mbs the member builder ( s ) representing member ( s ) .
* @ return this builder
*/
public ClassBuilder addMembers(MemberBuilder... mbs) {
for (MemberBuilder mb : mbs) {
members.add(mb);
mb.setClassName(fqn);
}
return this ;
}
/**
* Adds nested - classes , to an outer class to an outer builder .
* @ param cbs class builder ( s ) of the nested classes .
* @ return this builder .
*/
public ClassBuilder addNestedClasses(ClassBuilder... cbs) {
Stream.of(cbs).forEach(cb -> {
nested.add(cb);
cb.setClassName(fqn);
});
return this ;
}
/**
* Adds inner - classes , to an outer class builder .
* @ param cbs class builder ( s ) of the inner classes .
* @ return this builder .
*/
public ClassBuilder addInnerClasses(ClassBuilder... cbs) {
Stream.of(cbs).forEach(cb -> {
inners.add(cb);
cb.setClassName(fqn);
});
return this ;
}
@Override
public String toString() {
OutputWriter ow = new OutputWriter();
if (pkg != null )
ow.println("package " + pkg + ";" );
imports.forEach(i -> ow.println("import " + i + ";" ));
switch (comments.kind) {
case AUTO:
ow.println("/** Class " + fqn + " */");
break ;
case USER:
ow.println("/** ");
comments.comments.forEach(c -> ow.println(" * " + c));
ow.println(" */" );
break ;
case NO_API_COMMENT:
ow.println("// NO_API_COMMENT");
break ;
}
ow.print(modifiers.toString());
ow.print(clsname);
if (typeParameter != null ) {
ow.print(typeParameter + " " );
} else {
ow.print(" " );
}
if (extendsType != null && !extendsType.isEmpty()) {
ow.print("extends " + extendsType + " " );
}
if (!implementsTypes.isEmpty()) {
ow.print("implements " );
ListIterator<String> iter = implementsTypes.listIterator();
while (iter.hasNext()) {
String s = iter.next() ;
ow.print(s);
if (iter.hasNext())
ow.print(", " );
}
}
ow.print("{" );
if (!nested.isEmpty()) {
ow.println("" );
nested.forEach(m -> ow.println(m.toString()));
}
if (!members.isEmpty()) {
ow.println("" );
members.forEach(m -> ow.println(m.toString()));
}
ow.println("}" );
if (!inners.isEmpty()) {
ow.println(" {" );
inners.forEach(m -> ow.println(m.toString()));
ow.println("}" );
}
return ow.toString();
}
/**
* Writes out the java source for a type element . Package directories
* will be created as needed as inferred by the type name .
* @ param srcDir the top level source directory .
* @ throws IOException if an error occurs .
*/
public void write(Path srcDir) throws IOException {
Files.createDirectories(srcDir);
Path outDir = srcDir;
if (pkg != null && !pkg.isEmpty()) {
String pdir = pkg.replace("." , "/" );
outDir = Paths.get(srcDir.toString(), pdir);
Files.createDirectories(outDir);
}
Path filePath = Paths.get(outDir.toString(), clsname + ".java" );
tb.writeFile(filePath, this .toString());
}
/**
* The member builder , this is the base class for all types of members .
*/
public static abstract class MemberBuilder extends AbstractBuilder {
public MemberBuilder(Modifiers modifiers, String name) {
super (modifiers, name);
}
/**
* Sets the enclosing type ' s name .
* @ param className the enclosing type ' s name
*/
@Override
void setClassName(String className) {
cname = className;
}
/**
* Sets a comment for the element .
*
* @ param comments for any element
* @ return this builder .
*/
@Override
public MemberBuilder setComments(String... comments) {
super .setComments(comments);
return this ;
}
/**
* Sets a comment for the element . Typically used to set user ' s
* preferences whether an automatic comment is required or no API
* comment .
*
* @ param kind of comment , automatic or no comment .
* @ return this builder .
*/
@Override
public MemberBuilder setComments(Comment.Kind kind) {
super .setComments(kind);
return this ;
}
/**
* Sets a new modifier .
*
* @ param modifiers
* @ return this builder .
*/
@Override
public MemberBuilder setModifiers(String... modifiers) {
super .setModifiers(modifiers);
return this ;
}
}
/**
* The field builder .
*/
public static class FieldBuilder extends MemberBuilder {
private String fieldType;
private String value;
private static final Pattern FIELD_RE = Pattern.compile("(.*)(\\s*=\\s*)(.*)(;)" );
/**
* Constructs a field with the modifiers and name of the field .
* The builder by default is configured to auto generate the
* comments for the field .
* @ param name of the field
*/
public FieldBuilder(String name) {
super (new Modifiers(), name);
this .comments = new Comment(Comment.Kind.AUTO);
}
/**
* Returns a field builder by parsing the string .
* ex : public static String myPlayingField ;
* @ param fieldString describing the field .
* @ return a field builder .
*/
public static FieldBuilder parse(String fieldString) {
String prefix;
String value = null ;
Matcher m = FIELD_RE.matcher(fieldString);
if (m.matches()) {
prefix = m.group(1 ).trim();
value = m.group(3 ).trim();
} else {
int end = fieldString.lastIndexOf(';' ) > 0
? fieldString.lastIndexOf(';' )
: fieldString.length();
prefix = fieldString.substring(0 , end).trim();
}
List<String> list = Stream.of(prefix.split(" " ))
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
if (list.size() < 2 ) {
throw new IllegalArgumentException("incorrect field string: "
+ fieldString);
}
String name = list.get(list.size() - 1 );
String fieldType = list.get(list.size() - 2 );
FieldBuilder fb = new FieldBuilder(name);
fb.modifiers.setModifiers(list.subList(0 , list.size() - 2 ));
fb.setFieldType(fieldType);
if (value != null )
fb.setValue(value);
return fb;
}
/**
* Sets the modifiers for this builder .
*
* @ param mods
* @ return this builder
*/
public FieldBuilder setModifiers(String mods) {
this .modifiers.setModifiers(mods);
return this ;
}
/**
* Sets the type of the field .
* @ param fieldType the name of the type .
* @ return this field builder .
*/
public FieldBuilder setFieldType(String fieldType) {
this .fieldType = fieldType;
return this ;
}
public FieldBuilder setValue(String value) {
this .value = value;
return this ;
}
@Override
public String toString() {
String indent = " " ;
OutputWriter ow = new OutputWriter();
switch (comments.kind) {
case AUTO:
ow.println(indent + "/** Field " +
super .name + " in " + super .cname + " */" );
break ;
case INHERIT_DOC: case USER:
ow.println(indent + "/** " +
comments.toString() + " */" );
break ;
case NO_API_COMMENT:
ow.println(indent + "// NO_API_COMMENT");
break ;
}
ow.print(indent + super .modifiers.toString() + " " );
ow.print(fieldType + " " );
ow.print(super .name);
if (value != null ) {
ow.print(" = " + value);
}
ow.println(";" );
return ow.toString();
}
}
/**
* The method builder .
*/
public static class MethodBuilder extends MemberBuilder {
private final List<Pair> params;
private String returnType;
private List<String> body;
final static Pattern METHOD_RE = Pattern.compile("(.*)(\\()(.*)(\\))(.*)" );
/**
* Constructs a method builder . The builder by default is configured
* to auto generate the comments for this method .
* @ param name of the method .
*/
public MethodBuilder(String name) {
super (new Modifiers(), name);
comments = new Comment(Comment.Kind.AUTO);
params = new ArrayList<>();
body = null ;
}
/**
* Returns a method builder by parsing a string which
* describes a method .
* @ param methodString the method description .
* @ return a method builder .
*/
public static MethodBuilder parse(String methodString) {
Matcher m = METHOD_RE.matcher(methodString);
if (!m.matches())
throw new IllegalArgumentException("string does not match: "
+ methodString);
String prefix = m.group(1 );
String params = m.group(3 );
String suffix = m.group(5 ).trim();
if (prefix.length() < 2 ) {
throw new IllegalArgumentException("incorrect method string: "
+ methodString);
}
String[] pa = prefix.split(" " );
List<String> list = List.of(pa);
String name = list.get(list.size() - 1 );
String returnType = list.get(list.size() - 2 );
MethodBuilder mb = new MethodBuilder(name);
mb.modifiers.setModifiers(list.subList(0 , list.size() - 2 ));
mb.setReturn(returnType);
pa = params.split("," );
Stream.of(pa).forEach(p -> {
p = p.trim();
if (!p.isEmpty())
mb.addParameter(p);
});
if (!suffix.isEmpty() || suffix.length() > 1 ) {
mb.setBody(suffix);
}
return mb;
}
/**
* Sets the modifiers for this builder .
*
* @ param modifiers
* @ return this builder
*/
public MethodBuilder setModifiers(String modifiers) {
this .modifiers.setModifiers(modifiers);
return this ;
}
@Override
public MethodBuilder setComments(String... comments) {
super .setComments(comments);
return this ;
}
@Override
public MethodBuilder setComments(Comment.Kind kind) {
super .setComments(kind);
return this ;
}
/**
* Sets a return type for a method .
* @ param returnType the return type .
* @ return this method builder .
*/
public MethodBuilder setReturn(String returnType) {
this .returnType = returnType;
return this ;
}
/**
* Adds a parameter ( s ) to the method builder .
* @ param params a pair consisting of type and parameter name .
* @ return this method builder .
*/
public MethodBuilder addParameters(Pair... params) {
this .params.addAll(List.of(params));
return this ;
}
/**
* Adds a parameter to the method builder .
* @ param type the type of parameter .
* @ param name the parameter name .
* @ return this method builder .
*/
public MethodBuilder addParameter(String type, String name) {
this .params.add(new Pair(type, name));
return this ;
}
/**
* Adds a parameter to the method builder , by parsing the string .
* @ param s the parameter description such as " Double voltage "
* @ return this method builder .
*/
public MethodBuilder addParameter(String s) {
String[] p = s.trim().split(" " );
return addParameter(p[0 ], p[p.length - 1 ]);
}
/**
* Sets the body of the method , described by the string .
* Such as " { " , " double i = v / r ; " , " return i ; " , " } "
* @ param body of the methods
* @ return
*/
public MethodBuilder setBody(String... body) {
if (body == null ) {
this .body = null ;
} else {
this .body = new ArrayList<>();
this .body.addAll(List.of(body));
}
return this ;
}
@Override
public String toString() {
OutputWriter ow = new OutputWriter();
String indent = " " ;
switch (comments.kind) {
case AUTO:
ow.println(indent + "/** Method " + super.name + " in " + super.cname);
if (!params.isEmpty())
params.forEach(p -> ow.println(indent + " * @param " + p.second + " a param" ));
if (returnType != null && !returnType.isEmpty() && !returnType.contains("void" ))
ow.println(indent + " * @return returns something" );
ow.println(indent + " */" );
break ;
case INHERIT_DOC: case USER:
ow.println(indent + "/** " + comments.toString() + " */");
break ;
case NO_API_COMMENT:
ow.println(indent + "// NO_API_COMMENT");
break ;
}
ow.print(indent + super .modifiers.toString() + " " );
ow.print(returnType + " " );
ow.print(super .name + "(" );
if (!params.isEmpty()) {
ListIterator<Pair> iter = params.listIterator();
while (iter.hasNext()) {
Pair p = iter.next();
ow.print(p.first + " " + p.second);
if (iter.hasNext())
ow.print(", " );
}
}
ow.print(")" );
if (body == null ) {
ow.println(";" );
} else {
body.forEach(ow::println);
}
return ow.toString();
}
}
//A sample, to test with an IDE.
// public static void main(String... args) throws IOException {
// ClassBuilder cb = new ClassBuilder(new ToolBox(), "foo.bar.Test<C extends A>");
// cb.addModifiers("public", "abstract", "static")
// .addImports("java.io").addImports("java.nio")
// .setComments("A comment")
// .addImplements("Serialization", "Something")
// .setExtends("java.lang.Object")
// .addMembers(
// FieldBuilder.parse("public int xxx;"),
// FieldBuilder.parse("public int yyy = 10;"),
// MethodBuilder.parse("public static void main(A a, B b, C c);")
// .setComments("CC"),
// MethodBuilder.parse("void foo(){//do something}")
//
// );
// ClassBuilder ic = new ClassBuilder(new ToolBox(), "IC");
// cb.addModifiers( "interface");
// cb.addNestedClasses(ic);
// System.out.println(cb.toString());
// cb.write(Paths.get("src-out"));
// }
}
Messung V0.5 in Prozent C=86 H=93 G=89
¤ Dauer der Verarbeitung: 0.4 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland