一个Java API来生成Java源文件

我正在寻找一个框架来生成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); 

然后,应该在目标目录的子目录中find一个java源文件。

有谁知道这样的框架?


编辑

  1. 我真的需要源文件。
  2. 我也想填写方法的代码。
  3. 我正在寻找一个高层次的抽象,而不是直接的字节码操纵/生成。
  4. 我也需要在一个对象树中的“类的结构”。
  5. 问题领域是一般的:产生大量非常不同的类,没有“共同结构”。

解决scheme
我在CodeModel和Eclipse JDT中发布了2个答案。

我在我的解决scheme中使用了CodeModel 🙂

Sun提供了一个名为CodeModel的API,用于使用API​​生成Java源文件。 获取信息并不是最简单的事情,但它在那里,而且工作得非常好。

最简单的方法是作为JAXB 2 RI的一部分 – XJC模式到Java生成器使用CodeModel来生成它的Java源代码,它是XJC jar的一部分。 你只能用CodeModel来使用它。

http://codemodel.java.net/抓取它;

使用CodeModelfind解决scheme
谢谢, 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; } } 

使用Eclipse JDT的AST发现解决scheme
谢谢, 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(); } } 

您可以使用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; } } 

另一种select是Eclipse JDT的AST,如果您需要重写任意的Java源代码,而不是仅仅生成源代码,那么它是很好的select。 (我相信它可以独立使用日食)。

Eclipse JET项目可以用来做源代码。 我不认为它的API和你所描述的完全一样,但是每当我听说一个做Java源代码的项目时,他们都使用JET或本地工具。

不知道一个库,但通用的模板引擎可能是你所需要的。 其中有一堆 ,我个人对FreeMarker有很好的经验

我构build了一个非常类似于您的理论DSL(称为“sourcegen”)的东西,但在技术上而不是我写的ORM的util项目。 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

它还做了一些整洁的事情,例如在参数/返回types中“自动组织导入”任何FQCN,自动修剪在此代码运行中未触及的任何旧文件,正确地缩进内部类等。

这个想法是生成的代码应该很好看,没有任何警告(未使用的导入等),就像其他代码一样。 这么多生成的代码是丑陋的阅读…这是可怕的。

无论如何,没有太多的文档,但我认为这个API非常简单/直观。 如果有人感兴趣,Maven回购在这里 。

如果你真的需要来源,我不知道任何生成源的东西。 但是,您可以使用ASM或CGLIB来直接创build.class文件。

您可能能够从这些生成源,但我只用它们来生成字节码。

我自己做了一个模拟生成器工具。 这是一个非常简单的任务,即使您需要遵循Sun格式准则。 我敢打赌,你会完成更快的代码,然后在互联网上find适合你的目标。

你基本上已经概述了API。 只需填写实际的代码吧!

还有StringTemplate 。 这是由ANTLR的作者,是相当强大的。

有一个新的项目写一次 。 基于模板的代码生成器 您使用Groovy编写自定义模板,并根据javareflection生成文件。 这是生成任何文件的最简单的方法。 您可以通过生成AspectJ文件,基于JPA注释的SQL,基于枚举的插入/更新等来制作getters / settest / toString。

模板示例:

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

这实际上取决于你想要做什么。 代码生成本身就是一个主题。 如果没有特定的用例,我build议查看速度代码生成/模板库。 另外,如果你正在离线生成代码,我会build议使用像ArgoUML这样的东西从UML图/对象模型到Java代码。

例如: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 DIT 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//")); 

这是一个JSON-to-POJO项目,看起来很有趣:

http://www.jsonschema2pojo.org/