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.

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


РЕДАКТИРОВАТЬ:

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

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

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

Ваш вопрос очень общий, действительно ли ваша проблемная область такая общая? Не могли бы вы подробнее рассказать о своей проблемной области? Например, я написал инструменты генерации кода для генерации кода для конкретных задач, таких как устранение повторяющегося кода класса исключения или устранение дублирования в перечислениях.

Greg Mattes 23.09.2008 18:59

@Vlookward: вы можете переместить ответы, которые вы разместили в вопросе, как два отдельных ответа ниже. Затем добавьте ссылку на каждый из Вопросов.

Ande Turner 25.09.2008 21:34

@Banengusk: Спасибо, что спросили, сэкономили мне часы на поиск в самых темных уголках Интернета. @skaffman: Отличная находка - вы помогли другому разработчику легче справиться с его предстоящей задачей :)

Ran Biron 12.12.2009 21:38

Этот SO-ответ касается вопроса для C++, а не для Java, но ответ работает и для Java. stackoverflow.com/a/28103779/120163

Ira Baxter 26.01.2015 14:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
127
4
54 668
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

Если вам ДЕЙСТВИТЕЛЬНО нужен источник, я не знаю ничего, что генерирует источник. Однако вы можете использовать КАК М или CGLIB для непосредственного создания файлов .class.

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

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

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

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

Хе-хе-хе ... Если фреймворк не найдется, я его напишу. Хотелось бы много функционала, чтобы утром не получу ...

Daniel Fanjul 23.09.2008 19:20

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

Большой!! Я ищу абстрактное синтаксическое дерево ... Теперь я буду искать дополнительную информацию об API ... Спасибо !, :-)

Daniel Fanjul 23.09.2008 19:31

Как я и ожидал, API сложен. Но в нем есть вся необходимая мне функциональность. Спасибо, Джайлз.

Daniel Fanjul 23.09.2008 20:00

Как упоминал @gastaldi, roaster (из JBoss Forge) - хорошая оболочка для Eclipse JDT. Он скрывает сложность JDT и предоставляет удобный API для синтаксического анализа, изменения или написания кода Java. github.com/forge/roaster

Jmini 24.10.2014 17:04

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

Ответ принят как подходящий

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

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

Скачайте его из http://codemodel.java.net/

Это как раз то, что мне нужно! Просто и полностью функционально. Спасибо, скаффман!

Daniel Fanjul 24.09.2008 00:21

@BradCupit Согласно pom-файлу repo.maven.apache.org/maven2/com/sun/codemodel/codemodel/2.6‌ /…, это CDDL + GPL glassfish.java.net/public/CDDL+GPL_1_1.html

ykaganovich 18.04.2014 23:02

@ykaganovich Хороший звонок. Это [repo.maven.apache.org/maven2/com/sun/codemodel/… под лицензией CDDL и GPL). Я удалил свой предыдущий комментарий.

Brad Cupit 21.04.2014 17:56

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

Это выглядит потрясающе. Как создать метод, который возвращает другой тип, который также создается с помощью CodeModel?

András Hummer 11.09.2013 12:08

@DrH, простой поиск в Google: codemodel.java.net/nonav/apidocs/com/sun/codemodel/…

Daniel Fanjul 12.09.2013 12:50

@ AndrásHummer использует экземпляр, возвращаемый cm._class(...), в качестве аргумента возвращаемого типа для dc.method(...).

Hugo Baés 21.01.2015 21:52

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

Могу я спросить - вы сделали это как часть подключаемого модуля Java Eclipse или вам удалось использовать это как отдельный код? Я понимаю, что это уже много лет.

mtrc 21.06.2013 03:39

@mtrc Если я хорошо помню, это был автономный и нормальный java-проект в eclipse, добавляющий надлежащую банку в путь к классам, но я не помню имя файла.

Daniel Fanjul 22.06.2013 21:35

Также есть StringTemplate. Он разработан автором ANTLR и довольно мощный.

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

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

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

Появился новый проект напиши один раз. Генератор кода на основе шаблонов. Вы пишете собственный шаблон, используя Groovy, и генерируете файл в зависимости от отражений Java. Это самый простой способ создать любой файл. Вы можете создавать геттеры / 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;
    }
}

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

Вот интересный проект JSON-to-POJO:

http://www.jsonschema2pojo.org/

Другие вопросы по теме