Tuesday, February 8, 2011

A Java API to generate Java source files

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 sould be found in a subdirectory 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, :-)

  • ONJava has an article on code generation which might be of your interest. See http://www.onjava.com/pub/a/onjava/2003/09/03/generation.html

    From Rolf
  • 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.

    Banengusk : I really need the source files. Thanks!
    From Steve g
  • 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.

    http://www.eclipse.org/modeling/m2t/?project=jet

    From Mike Deck
  • If you can't find such a library, it seems like it would be pretty simple to build yourself, it's just a matter of outputting text in the correct format. I'm assuming you just want to build the skeleton, and not actually fill out the code in the methods?

    Banengusk : I also would like to fill out the code of the methods. :-)
    From davr
  • 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!

    Banengusk : 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...
  • 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).

    Banengusk : Great!! An Abstract Syntax Tree is what I'm looking for... Now I will search more info about the API... Thanks!, :-)
    Banengusk : The API is complex, as I expected. But it has all the functionality I need. Thanks, Giles.
    From Squirrel
  • 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

  • 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.dev.java.net

    Banengusk : It is just what I need! Simple and fully functional. Thanks, skaffman!
    From skaffman
  • 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;
        }
    }
    
    From Banengusk
  • 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();
      }
    }
    
    From Banengusk
  • There is also StringTemplate. It is by the author of ANTLR and is quite powerful.

    From Bala

0 comments:

Post a Comment