A Java API to generate Java source files

JavaEclipseCode Generation

Java Problem Overview


I'm looking for a framework to generate Java source files.

Something like the following API:

X clazz = Something.createClass("package name", "class name");
clazz.addSuperInterface("interface name");
clazz.addMethod("method name", returnType, argumentTypes, ...);

File targetDir = ...;
clazz.generate(targetDir);

Then, a java source file should be found in a sub-directory of the target directory.

Does anyone know such a framework?


EDIT:

  1. I really need the source files.
  2. I also would like to fill out the code of the methods.
  3. I'm looking for a high-level abstraction, not direct bytecode manipulation/generation.
  4. I also need the "structure of the class" in a tree of objects.
  5. The problem domain is general: to generate a large amount of very different classes, without a "common structure".

SOLUTIONS
I have posted 2 answers based in your answers... with CodeModel and with Eclipse JDT.

I have used CodeModel in my solution, :-)

Java Solutions


Solution 1 - Java

Sun provides an API called CodeModel for generating Java source files using an API. It's not the easiest thing to get information on, but it's there and it works extremely well.

The easiest way to get hold of it is as part of the JAXB 2 RI - the XJC schema-to-java generator uses CodeModel to generate its java source, and it's part of the XJC jars. You can use it just for the CodeModel.

Grab it from http://codemodel.java.net/

Solution 2 - Java

Solution found with CodeModel
Thanks, skaffman.

For example, with this code:

JCodeModel cm = new JCodeModel();
JDefinedClass dc = cm._class("foo.Bar");
JMethod m = dc.method(0, int.class, "foo");
m.body()._return(JExpr.lit(5));

File file = new File("./target/classes");
file.mkdirs();
cm.build(file);

I can get this output:

package foo;
public class Bar {
    int foo() {
        return  5;
    }
}

Solution 3 - Java

Solution found with Eclipse JDT's AST
Thanks, Giles.

For example, with this code:

AST ast = AST.newAST(AST.JLS3);
CompilationUnit cu = ast.newCompilationUnit();

PackageDeclaration p1 = ast.newPackageDeclaration();
p1.setName(ast.newSimpleName("foo"));
cu.setPackage(p1);

ImportDeclaration id = ast.newImportDeclaration();
id.setName(ast.newName(new String[] { "java", "util", "Set" }));
cu.imports().add(id);

TypeDeclaration td = ast.newTypeDeclaration();
td.setName(ast.newSimpleName("Foo"));
TypeParameter tp = ast.newTypeParameter();
tp.setName(ast.newSimpleName("X"));
td.typeParameters().add(tp);
cu.types().add(td);

MethodDeclaration md = ast.newMethodDeclaration();
td.bodyDeclarations().add(md);

Block block = ast.newBlock();
md.setBody(block);

MethodInvocation mi = ast.newMethodInvocation();
mi.setName(ast.newSimpleName("x"));

ExpressionStatement e = ast.newExpressionStatement(mi);
block.statements().add(e);

System.out.println(cu);

I can get this output:

package foo;
import java.util.Set;
class Foo<X> {
  void MISSING(){
    x();
  }
}

Solution 4 - Java

You can use Roaster (https://github.com/forge/roaster) to do code generation.

Here is an example:

JavaClassSource source = Roaster.create(JavaClassSource.class);
source.setName("MyClass").setPublic();
source.addMethod().setName("testMethod").setPrivate().setBody("return null;")
           .setReturnType(String.class).addAnnotation(MyAnnotation.class);
System.out.println(source);

will display the following output:

public class MyClass {
   private String testMethod() {
       return null;
   }
}

Solution 5 - Java

Another alternative is Eclipse JDT's AST which is good if you need to rewrite arbitrary Java source code rather than just generate source code. (and I believe it can be used independently from eclipse).

Solution 6 - Java

The Eclipse JET project can be used to do source generation. I don't think it's API is exactly like the one you described, but every time I've heard of a project doing Java source generation they've used JET or a homegrown tool.

Solution 7 - Java

Don't know of a library, but a generic template engine might be all you need. There are a bunch of them, I personally have had good experience with FreeMarker

Solution 8 - Java

I built something that looks very much like your theoretical DSL, called "sourcegen", but technically instead of a util project for an ORM I wrote. The DSL looks like:

@Test
public void testTwoMethods() {
    GClass gc = new GClass("foo.bar.Foo");

    GMethod hello = gc.getMethod("hello");
    hello.arguments("String foo");
    hello.setBody("return 'Hi' + foo;");

    GMethod goodbye = gc.getMethod("goodbye");
    goodbye.arguments("String foo");
    goodbye.setBody("return 'Bye' + foo;");

    Assert.assertEquals(
    Join.lines(new Object[] {
        "package foo.bar;",
        "",
        "public class Foo {",
        "",
        "    public void hello(String foo) {",
        "        return \"Hi\" + foo;",
        "    }",
        "",
        "    public void goodbye(String foo) {",
        "        return \"Bye\" + foo;",
        "    }",
        "",
        "}",
        "" }),
    gc.toCode());
}

https://github.com/stephenh/joist/blob/master/util/src/test/java/joist/sourcegen/GClassTest.java

It also does some neat things like "Auto-organize imports" any FQCNs in parameters/return types, auto-pruning any old files that were not touched in this codegen run, correctly indenting inner classes, etc.

The idea is that generated code should be pretty to look at it, with no warnings (unused imports, etc.), just like the rest of your code. So much generated code is ugly to read...it's horrible.

Anyway, there is not a lot of docs, but I think the API is pretty simple/intuitive. The Maven repo is here if anyone is interested.

Solution 9 - Java

If you REALLY need the source, I don't know of anything that generates source. You can however use ASM or CGLIB to directly create the .class files.

You might be able to generate source from these, but I've only used them to generate bytecode.

Solution 10 - Java

I was doing it myself for a mock generator tool. It's a very simple task, even if you need to follow Sun formatting guidelines. I bet you'd finish the code that does it faster then you found something that fits your goal on the Internet.

You've basically outlined the API yourself. Just fill it with the actual code now!

Solution 11 - Java

There is also StringTemplate. It is by the author of ANTLR and is quite powerful.

Solution 12 - Java

There is new project write-it-once. Template based code generator. You write custom template using Groovy, and generate file depending on java reflections. It's the simplest way to generate any file. You can make getters/settest/toString by generating AspectJ files, SQL based on JPA annotations, inserts / updates based on enums and so on.

Template example:

package ${cls.package.name};

public class ${cls.shortName}Builder {

    public static ${cls.name}Builder builder() {
        return new ${cls.name}Builder();
    }
<% for(field in cls.fields) {%>
    private ${field.type.name} ${field.name};
<% } %>
<% for(field in cls.fields) {%>
    public ${cls.name}Builder ${field.name}(${field.type.name} ${field.name}) {
        this.${field.name} = ${field.name};
        return this;
    }
<% } %>
    public ${cls.name} build() {
        final ${cls.name} data = new ${cls.name}();
<% for(field in cls.fields) {%>
        data.${field.setter.name}(this.${field.name});
<% } %>
        return data;
    }
}

Solution 13 - Java

It really depends on what you are trying to do. Code generation is a topic within itself. Without a specific use-case, I suggest looking at velocity code generation/template library. Also, if you are doing the code generation offline, I would suggest using something like ArgoUML to go from UML diagram/Object model to Java code.

Solution 14 - Java

Exemple : 1/

private JFieldVar generatedField;

2/

String className = "class name";
		/* package name */
		JPackage jp = jCodeModel._package("package name ");
		 /*  class name  */
        JDefinedClass jclass = jp._class(className);
        /* add comment */
        JDocComment jDocComment = jclass.javadoc();
        jDocComment.add("By AUTOMAT D.I.T tools : " + new Date() +" => " + className);
        // génération des getter & setter & attribues

        	// create attribue 
        	 this.generatedField = jclass.field(JMod.PRIVATE, Integer.class) 
        			 , "attribue name ");
        	 // getter
        	 JMethod getter = jclass.method(JMod.PUBLIC, Integer.class) 
        			 , "attribue name ");
        	 getter.body()._return(this.generatedField);
        	 // setter
        	 JMethod setter = jclass.method(JMod.PUBLIC, Integer.class) 
        			 ,"attribue name ");
        	 // create setter paramétre 
        	 JVar setParam = setter.param(getTypeDetailsForCodeModel(Integer.class,"param name");
        	 // affectation  ( this.param = setParam ) 
        	 setter.body().assign(JExpr._this().ref(this.generatedField), setParam);
     
        jCodeModel.build(new File("path c://javaSrc//"));

Solution 15 - Java

Here is a JSON-to-POJO project that looks interesting:

http://www.jsonschema2pojo.org/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaniel FanjulView Question on Stackoverflow
Solution 1 - JavaskaffmanView Answer on Stackoverflow
Solution 2 - JavaDaniel FanjulView Answer on Stackoverflow
Solution 3 - JavaDaniel FanjulView Answer on Stackoverflow
Solution 4 - JavagastaldiView Answer on Stackoverflow
Solution 5 - JavaSquirrelView Answer on Stackoverflow
Solution 6 - JavaMike DeckView Answer on Stackoverflow
Solution 7 - JavaykaganovichView Answer on Stackoverflow
Solution 8 - JavaStephen HabermanView Answer on Stackoverflow
Solution 9 - JavaSteve gView Answer on Stackoverflow
Solution 10 - JavaVladimir DyuzhevView Answer on Stackoverflow
Solution 11 - JavaBalaView Answer on Stackoverflow
Solution 12 - JavaAtmegaView Answer on Stackoverflow
Solution 13 - JavaBerlin BrownView Answer on Stackoverflow
Solution 14 - Javauser3207181View Answer on Stackoverflow
Solution 15 - JavamtysonView Answer on Stackoverflow