一个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源文件。
有谁知道这样的框架?
编辑 :
- 我真的需要源文件。
- 我也想填写方法的代码。
- 我正在寻找一个高层次的抽象,而不是直接的字节码操纵/生成。
- 我也需要在一个对象树中的“类的结构”。
- 问题领域是一般的:产生大量非常不同的类,没有“共同结构”。
解决scheme
我在CodeModel和Eclipse JDT中发布了2个答案。
我在我的解决scheme中使用了CodeModel 🙂
Sun提供了一个名为CodeModel的API,用于使用API生成Java源文件。 获取信息并不是最简单的事情,但它在那里,而且工作得非常好。
最简单的方法是作为JAXB 2 RI的一部分 – XJC模式到Java生成器使用CodeModel来生成它的Java源代码,它是XJC jar的一部分。 你只能用CodeModel来使用它。
使用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项目,看起来很有趣: