一个用来生成Java源代码的Java API

130

我正在寻找一个能生成Java源文件的框架。

类似于以下API:

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

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

然后,在目标目录的子目录中应该可以找到一个Java源代码文件。

有人知道这样的框架吗?


编辑

  1. 我确实需要源代码文件。
  2. 我也想填写方法的代码。
  3. 我正在寻找高级抽象,而不是直接操作/生成字节码。
  4. 我还需要“类的结构”以对象树的形式呈现。
  5. 问题域是一般的:生成大量非常不同的类,没有“通用结构”。

解决方案
我已经发布了两个答案,基于您的答案...使用CodeModel使用Eclipse JDT

我在我的解决方案中使用了CodeModel,:-)


你的问题非常泛泛,你的问题领域真的这么广泛吗?你能更具体地描述你的问题领域吗?例如,我编写了代码生成工具,用于为特定问题生成代码,如消除重复的异常类代码或枚举中的重复项。 - Greg Mattes
@Vlookward:你可以把你已经放在问题中的答案作为两个单独的答案移到下面。然后从问题中添加一个链接到每个答案。 - Ande Turner
@Banengusk:谢谢你的提问,省去了我在互联网最黑暗的角落搜索数小时的时间。 @skaffman:太棒了,你让另一个开发者对即将到来的任务更加放心了 :) - Ran Biron
这个SO答案解决了C++而不是Java的问题,但是答案同样适用于Java。https://dev59.com/JIfca4cB1Zd3GeqPfSxI#28103779 - Ira Baxter
15个回答

70

Sun提供了一个名为CodeModel的API,可使用该API生成Java源文件。获取有关它的信息并不容易,但它确实存在,并且非常有效。

获得它的最简单方法是作为JAXB 2 RI的一部分 - XJC模式到Java生成器使用CodeModel生成其Java源代码,并且它是XJC Jars的一部分。 您可以仅使用CodeModel。

http://codemodel.java.net/获取它。


2
这正是我所需要的!简单且功能齐全。谢谢,skaffman! - Daniel Fanjul
1
根据pom文件http://repo.maven.apache.org/maven2/com/sun/codemodel/codemodel/2.6/codemodel-2.6.pom,它是CDDL + GPL https://glassfish.java.net/public/CDDL+GPL_1_1.html。 - ykaganovich
@ykaganovich 好的建议。它是[http://repo.maven.apache.org/maven2/com/sun/codemodel/codemodel-project/2.6/codemodel-project-2.6.pom](在 CDDL 和 GPL 下双重许可)。我已经删除了早先的评论。 - Brad Cupit

46

使用 CodeModel 找到解决方案
感谢 skaffman

例如,使用以下代码:

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);
我可以得到这个输出:
package foo;
public class Bar {
    int foo() {
        return  5;
    }
}

这看起来很棒。你如何生成一个返回使用CodeModel生成的另一种类型的方法? - András Hummer
@DrH,简单的谷歌搜索:http://codemodel.java.net/nonav/apidocs/com/sun/codemodel/JDefinedClass.html#method(int,%20com.sun.codemodel.JType,%20java.lang.String) - Daniel Fanjul
@AndrásHummer 使用从 cm._class(...) 返回的实例作为 dc.method(...) 的返回类型参数。 - Hugo Baés

28

使用Eclipse JDT的AST找到解决方案
感谢Giles

例如,使用以下代码:

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

我可以获取到这个输出:
package foo;
import java.util.Set;
class Foo<X> {
  void MISSING(){
    x();
  }
}

我可以问一下吗?你是作为Java Eclipse插件的一部分完成这个还是成功地将其作为独立代码使用?我意识到这已经过去多年了。 - mtrc
如果我没记错的话,它是一个在Eclipse中独立且普通的Java项目,只需将正确的jar添加到类路径中即可 - 但我不记得文件名了。 - Daniel Fanjul

19

你可以使用Roaster(https://github.com/forge/roaster)来进行代码生成。

以下是一个例子:

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

将显示以下输出:

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

9
另一种选择是Eclipse JDT的AST,如果你需要重写任意Java源代码而不仅仅是生成源代码,则它非常好。(我相信它可以独立于eclipse使用)。

1
太好了!抽象语法树正是我要找的...现在我会搜索更多关于API的信息...谢谢!:-) - Daniel Fanjul
API非常复杂,正如我预料的那样。但它具备我所需的所有功能。谢谢,吉尔斯。 - Daniel Fanjul
1
正如 @gastaldi 所提到的,roaster(来自 JBoss Forge)是 Eclipse JDT 的一个很好的封装。它隐藏了 JDT 的复杂性,并提供了一个漂亮的 API 来解析、修改或编写 Java 代码。https://github.com/forge/roaster - Jmini

4

Eclipse JET 项目可用于进行源代码生成。虽然它的 API 可能与您描述的不完全相同,但每当我听说有项目进行 Java 源代码生成时,他们都使用 JET 或自行开发的工具。


3

不知道是否有专门的库,但通用的模板引擎可能是你所需要的。有许多模板引擎可供选择,个人建议使用FreeMarker,我在使用过程中有良好的体验。


2

我建立了一个非常类似于您理论上的DSL的东西,叫做“sourcegen”,但技术上来说,它实际上是我编写的ORM工具项目,DSL的格式如下:

@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

此外,它还可以执行一些很棒的操作,例如“自动组织导入”参数/返回类型中的任何FQCN,自动修剪在此代码生成运行中未被触及的任何旧文件,正确缩进内部类等。

这个想法是生成的代码应该看起来漂亮,没有警告(未使用的导入等),就像您的其他代码一样。那么多生成的代码难以阅读...太可怕了。

无论如何,文档不多,但我认为API相当简单/直观。如果有人感兴趣,Maven存储库在这里


1

还有StringTemplate。它是ANTLR的作者创建的,非常强大。


1

如果你真的需要源代码,我不知道有什么可以生成源代码的工具。但是你可以使用ASMCGLIB直接创建.class文件。

你可能可以从这些文件中生成源代码,但我只用过它们来生成字节码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接