API Java для генерации исходных файлов 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);

Затем исходный файл java должен быть найден в подкаталоге целевого каталога.

Кто-нибудь знает такую ​​структуру?


ИЗМЕНИТЬ

  • Мне действительно нужны исходные файлы.
  • Я также хотел бы заполнить код методов.
  • Я ищу абстракцию высокого уровня, а не прямую манипуляцию/генерацию байт-кода.
  • Мне также нужна "структура класса" в дереве объектов.
  • Проблемная область является общей: для генерации большого количества очень разных классов без "общей структуры".

РЕШЕНИЯ
Я написал 2 ответы на основе ваших ответов... с CodeModel и с Eclipse JDT.

Я использовал CodeModel в своем решении: -)

Ответ 1

Sun предоставляет API под названием CodeModel для генерации исходных файлов Java с использованием API. Это не самая легкая вещь для получения информации, но она там и работает очень хорошо.

Самый простой способ получить это как часть JAXB 2 RI - генератор схемы от JJX-Java использует CodeModel для генерации своего java-источника и его части XJC-банок. Вы можете использовать его только для CodeModel.

Возьмите его из http://codemodel.java.net/

Ответ 2

Решение найдено с помощью 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;
    }
}

Ответ 3

Решение найдено с 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();
  }
}

Ответ 4

Вы можете использовать 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;
   }
}

Ответ 5

Другой альтернативой является Eclipse JDT AST, которая хороша, если вам нужно переписать произвольный исходный код Java, а не просто генерировать исходный код. (и я считаю, что он может использоваться независимо от eclipse).

Ответ 6

Проект Eclipse JET может использоваться для создания источника. Я не думаю, что API такой же, как тот, который вы описали, но каждый раз, когда я слышал о проекте, использующем исходное поколение Java, они использовали JET или домашний инструмент.

Ответ 7

Не знаю библиотеки, но генератор шаблонов может быть всем, что вам нужно. Есть кучка из них, у меня лично был хороший опыт работы с FreeMarker

Ответ 8

Я построил что-то, что очень похоже на ваш теоретический 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 repo здесь, если кому-то интересно.

Ответ 9

Если вам действительно нужен источник, я не знаю ничего, что генерирует источник. Однако вы можете использовать ASM или CGLIB для непосредственного создания файлов .class.

Возможно, вы сможете генерировать исходный код из них, но я использовал их только для генерации байт-кода.

Ответ 10

Я делал это сам для макета генератора. Это очень простая задача, даже если вам нужно следовать инструкциям по форматированию Sun. Бьюсь об заклад, вы закончите код, который сделает это быстрее, чем вы нашли что-то, что соответствует вашей цели в Интернете.

Вы в основном описали API самостоятельно. Просто заполните его фактическим кодом сейчас!

Ответ 11

Существует также StringTemplate. Это автор ANTLR и достаточно силен.

Ответ 12

Появился новый проект write-it-once. Генератор кода на основе шаблонов. Вы пишете настраиваемый шаблон с помощью Groovy и создаете файл в зависимости от java-отражений. Это самый простой способ создания любого файла. Вы можете создать getters/settest/toString, создав файлы AspectJ, SQL на основе аннотаций JPA, вставки/обновления на основе перечислений и т.д.

Пример шаблона:

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

Ответ 13

Это действительно зависит от того, что вы пытаетесь сделать. Генерация кода - это тема внутри себя. Без конкретного варианта использования я предлагаю просмотреть библиотеку генерации скоростей/шаблонов. Кроме того, если вы создаете генерацию кода в автономном режиме, я бы предложил использовать что-то вроде ArgoUML, чтобы перейти от UML-диаграммы/модели объекта к Java-коду.

Ответ 14

Пример: 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//"));