it-roy-ru.com

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

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

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


ПРАВКА:

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

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

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

123
Daniel Fanjul

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

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

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

69
skaffman

Решение найдено с помощью CodeModel
Спасибо, Скаффман .

Например, с этим кодом:

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;
    }
}
44
Daniel Fanjul

Решение найдено с помощью Eclipse JDT AST
Спасибо, Джайлс .

Например, с этим кодом:

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();
  }
}
27
Daniel Fanjul

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

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

9
Squirrel

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

4
Mike Deck

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

3
ykaganovich

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

2
Stephen Haberman

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

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

1
Steve g

Есть новый проект напиши один раз . Генератор кода на основе шаблонов. Вы пишете пользовательский шаблон, используя 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;
    }
}
1
Atmega

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

1
Bala

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

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

1
Vladimir Dyuzhev

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

0
Berlin Brown

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

Вот проект JSON-to-POJO, который выглядит интересно:

http://www.jsonschema2pojo.org/

0
mtyson