Java API生成Java源文件


127

我正在寻找一个生成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. 问题域是通用的:生成大量非常不同的类,而没有“通用结构”。

解决方案
我已经根据您的答案发布了2个答案... CodeModelEclipse JDT

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


您的问题很笼统,您的问题领域真的是这样吗?您能否更具体地说明您的问题域?例如,我编写了代码生成工具来针对特定问题生成代码,例如消除重复的异常类代码或消除枚举中的重复。
格雷格·马特斯

@Vlookward:您可以将已放入问题中的答案作为以下两个单独的答案移动。然后为每个问题添加一个链接。
安德·特纳

@Banengusk:感谢您的提问,为我节省了搜索互联网最黑暗区域的时间。@skaffman:很棒的发现-您使另一位开发人员可以轻松完成他即将完成的任务:)
Ran Biron 2009年

SO的答案是针对C ++而不是Java的问题,但是答案也适用于Java。 stackoverflow.com/a/28103779/120163
Ira Baxter

Answers:


70

Sun提供了一个称为CodeModel的API,用于使用API​​生成Java源文件。这不是最容易获得信息的事情,但是它就在那里而且效果非常好。

最简单的方法是将其作为JAXB 2 RI的一部分-XJC模式到Java生成器使用CodeModel生成其Java源,它是XJC jars的一部分。您可以仅将其用于CodeModel。

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


2
这就是我所需要的!简单且功能齐全。谢谢,夫!
Daniel Fanjul


@ykaganovich拜托。它是[ repo.maven.apache.org/maven2/com/sun/codemodel/…根据CDDL和GPL许可的)。我删除了之前的评论。
布拉德·库皮

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ásHummer使用从cm._class(...)返回的实例作为的返回类型参数dc.method(...)
HugoBaés,2015年

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

@mtrc如果我记得很好,那是eclipse中的一个独立的普通Java项目,将适当的jar添加到类路径中-但我不记得文件名了。
Daniel Fanjul 2013年

17

您可以使用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源代码而不是仅生成源代码,则该方法很好。(我相信它可以独立于日食使用)。


1
大!!我正在寻找抽象语法树...现在,我将搜索有关API的更多信息...谢谢!,:-)
Daniel Fanjul

如我所料,该API很复杂。但是它具有我需要的所有功能。谢谢,吉尔斯。
Daniel Fanjul

1
如@gastaldi所述,roaster(来自JBoss Forge)是Eclipse JDT的不错包装。它隐藏了JDT的复杂性,并提供了一个不错的API来解析,修改或编写Java代码。github.com/forge/roaster
Jmini

4

Eclipse的JET项目可以用来做源代码的生成。我认为它的API与您描述的API并不完全相同,但是每次我听到一个进行Java源代码生成的项目时,他们都使用JET或自家开发的工具。



2

我构建了一个非常类似于理论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

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

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

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


1

如果您确实需要该来源,那么我什么都不知道会产生该来源。但是,您可以使用ASMCGLIB直接创建.class文件。

您也许可以从这些文件生成源,但是我只用它们来生成字节码。


1

我自己是为模拟生成器工具来做的。即使您需要遵循Sun格式化准则,这也是一项非常简单的任务。我敢打赌,您会更快地完成执行该代码的代码,然后在Internet上找到适合您目标的内容。

您基本上已经自己概述了API。立即填写实际代码!


呵呵...如果找不到框架,那我要写它。我想要很多功能,所以我不会在早上得到它
Daniel Fanjul


1

有一个新的项目一次写入。基于模板的代码生成器。您可以使用Groovy编写自定义模板,并根据Java反射生成文件。这是生成任何文件的最简单方法。您可以通过生成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;
    }
}

0

这实际上取决于您要执行的操作。代码生成本身就是一个主题。如果没有特定的用例,建议您查看速度代码生成/模板库。另外,如果您要离线进行代码生成,我建议您使用ArgoUML之类的工具从UML图/对象模型转换为Java代码。


0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.