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 должен быть найден в подкаталоге целевого каталога.
кто-нибудь знает такие рамки?
EDIT:
- мне действительно нужны исходные файлы.
- я также хотел бы заполнить код методов.
- я смотрю для абстракции высокого уровня, а не прямой байт-код манипуляции/генерации.
- мне также нужна "структура класса" в дереве объектов.
- проблемная область является общей: для генерации большого количества очень разных классов, без "общей структуры".
решений
Я опубликовал 2 ответа, основанные на ваших ответах... с CodeModel и с Eclipse JDT.
я использовал CodeModel в моем решении :-)
15 ответов:
Sun предоставляет API под названием CodeModel для создания исходных файлов Java с помощью API. Это не самая простая вещь, чтобы получить информацию, но она есть, и она работает очень хорошо.
самый простой способ получить его как часть JAXB 2 RI-генератор XJC schema-to-java использует CodeModel для генерации своего источника java, и это часть jars XJC. Вы можете использовать его только для кодовой модели.
возьмите его из http://codemodel.java.net/
решение найдено с помощью 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; } }
решение найдено с помощью Eclipse JDT, предназначенным в АСТ
Спасибо,Джайлз.например, с таким кодом:
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; } }
Другой альтернативой является AST Eclipse JDT, который хорош, если вам нужно переписать произвольный исходный код Java, а не просто генерировать исходный код. (и я считаю, что его можно использовать независимо от eclipse).
The Eclipse JET проект может быть использован для создания исходного кода. Я не думаю, что это API точно так же, как тот, который вы описали, но каждый раз, когда я слышал о проекте, создающем исходное поколение Java, они использовали JET или доморощенный инструмент.
Не знаю библиотеки, но универсальный шаблонный движок может быть все, что вам нужно. Есть их куча, у меня лично был хороший опыт работы с FreeMarker
Я построил что-то, что очень похоже на ваш теоретический DSL, называемый "sourcegen", но технически вместо проекта util для 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
Он также делает некоторые аккуратные вещи, такие как "автоматическая организация импорта" любых FQCNs в параметрах / типах возврата, автоматическая обрезка любых старых файлов, которые не были затронуты в этом codegen запуск, правильное отступление внутренних классов и т. д.
идея заключается в том, что сгенерированный код должен быть довольно смотреть на него, без предупреждений (неиспользуемый импорт и т. д.), как и остальная часть вашего кода. Так много сгенерированного кода некрасиво read...it-это ужасно.
в любом случае, существует не так много документов, но я думаю, что API довольно прост/интуитивно понятен. РЕПО Maven-это здесь если кому-то интересно.
Я делал это сам для макета генератора инструмента. Это очень простая задача, даже если вам нужно следовать рекомендациям по форматированию Sun. Я уверен, что вы закончите код, который делает это быстрее, чем вы нашли что-то, что соответствует вашей цели в Интернете.
вы в основном изложили API самостоятельно. Просто заполните его с фактическим кодом сейчас!
есть еще StringTemplate. Это автор ANTLR и довольно мощный.
новый проект написать-это-один раз. Генератор кода на основе шаблона. Вы пишете пользовательский шаблон с помощью в 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; } }
Это действительно зависит от того, что вы пытаетесь сделать. Генерация кода-это тема сама по себе. Без конкретного случая использования я предлагаю посмотреть на библиотеку генерации/шаблонов кода скорости. Кроме того, если вы делаете генерацию кода в автономном режиме, я бы предложил использовать что-то вроде ArgoUML для перехода от UML-диаграммы/объектной модели к Java-коду.
Exemple : 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//"));