A Java API to generate Java source files [closed]
Asked Answered
M

15

130

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, :-)

Myrtia answered 23/9, 2008 at 14:26 Comment(4)
Your question is very general, is your problem domain really this general? Can you be more specific about your problem domain? For example, I've written code generation tools to generate code for specific problems like eliminating duplicate exception class code, or eliminating duplication in enums.Arletha
@Vlookward: You could move the answers which you have placed in the Question as 2 seperate answers below. Then add a link to each from the Question.Gnathion
@Banengusk: Thanks for asking, saved me hours of searching the darkest parts of the internet. @skaffman: Great find - you made another developer more at ease with his upcoming task :)Ceil
This SO answer addresses the question for C++ rather than Java, but the answer works for Java, also. https://mcmap.net/q/175391/-elegant-way-for-c-code-generationFreed
C
70

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/

Chem answered 23/9, 2008 at 16:41 Comment(3)
It is just what I need! Simple and fully functional. Thanks, skaffman!Myrtia
@BradCupit According to the pom file repo.maven.apache.org/maven2/com/sun/codemodel/codemodel/2.6/…, it is CDDL + GPL glassfish.java.net/public/CDDL+GPL_1_1.htmlChemoreceptor
@Chemoreceptor Good call. It's [repo.maven.apache.org/maven2/com/sun/codemodel/… licensed under CDDL and GPL). I removed my earlier comment.Topheavy
M
46

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;
    }
}
Myrtia answered 25/9, 2008 at 20:53 Comment(3)
This looks awesome. How do you generate a method that returns another type that is being generated with CodeModel as well?Lindner
@DrH, simple google search: codemodel.java.net/nonav/apidocs/com/sun/codemodel/…Myrtia
@AndrásHummer use the instance returned from cm._class(...) as return type argument for dc.method(...).Remodel
M
28

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();
  }
}
Myrtia answered 25/9, 2008 at 20:54 Comment(2)
Can I ask - did you do this as part of a Java Eclipse Plugin or did you manage to use this as standalone code? I realise this is years old.Brag
@Brag If I remember well, it was a standalone and normal java project in eclipse, adding the proper jar to the classpath - but I don't remember the filename.Myrtia
K
19

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;
   }
}
Knothole answered 23/9, 2008 at 14:26 Comment(0)
P
9

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).

Pomace answered 23/9, 2008 at 14:26 Comment(3)
Great!! An Abstract Syntax Tree is what I'm looking for... Now I will search more info about the API... Thanks!, :-)Myrtia
The API is complex, as I expected. But it has all the functionality I need. Thanks, Giles.Myrtia
As mentioned by @gastaldi, roaster (from JBoss Forge) is a nice wrapper for Eclipse JDT. It hides the complexity of the JDT and provide a nice API to parse, modify or write java code. github.com/forge/roasterAshton
P
4

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.

Priory answered 23/9, 2008 at 14:37 Comment(0)
C
3

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

Chemoreceptor answered 23/9, 2008 at 15:25 Comment(0)
B
2

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.

Boony answered 23/9, 2008 at 14:26 Comment(0)
B
1

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;
    }
}
Bartlet answered 23/9, 2008 at 14:26 Comment(0)
S
1

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

Sauder answered 23/9, 2008 at 14:26 Comment(0)
N
1

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.

Neckar answered 23/9, 2008 at 14:32 Comment(0)
C
1

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!

Chipper answered 23/9, 2008 at 15:0 Comment(1)
Hehehe... If no framework is found then I am going to write it. I would like a lot of functionality so I won't get it in a morning...Myrtia
D
0

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

http://www.jsonschema2pojo.org/

Disturbing answered 23/9, 2008 at 14:26 Comment(0)
H
0

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//"));
Hermilahermina answered 23/9, 2008 at 14:26 Comment(0)
P
0

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.

Promycelium answered 23/9, 2008 at 14:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.