API Java для создания исходных файлов Java [закрыто]
-
02-07-2019 - |
Вопрос
Я ищу платформу для создания исходных файлов 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.
я использовал Модель кода в моем решении, :-)
Решение
Sun предоставляет API под названием CodeModel для создания исходных файлов Java с помощью API.Получить информацию не так просто, но она есть и работает очень хорошо.
Самый простой способ получить его - это часть JAXB 2 RI: генератор схемы XJC в Java использует CodeModel для генерации исходного кода Java, и он является частью jar-файлов XJC.Вы можете использовать его только для CodeModel.
Возьмите это из http://codemodel.java.net/
Другие советы
Решение найдено с помощью 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;
}
}
Решение найдено с помощью AST 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();
}
}
Вы можете использовать Ростер (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, а не просто генерировать исходный код.(и я считаю, что его можно использовать независимо от затмения).
А Затмение Джет проект можно использовать для генерации исходного кода.Я не думаю, что этот API точно такой же, как тот, который вы описали, но каждый раз, когда я слышал о проекте, выполняющем генерацию исходного кода Java, они использовали JET или собственный инструмент.
Не знаю библиотеки, но универсальный механизм шаблонов может быть всем, что вам нужно.Есть их куча, у меня лично был хороший опыт работы с FreeMarker
Я создал нечто, очень похожее на ваш теоретический 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
Он также делает некоторые изящные вещи, такие как «автоматическая организация импорта» любых полных доменных имен в параметрах/типах возвращаемых данных, автоматическое удаление всех старых файлов, которые не были затронуты в этом запуске кодогенерации, правильное отступы внутренних классов и т. д.
Идея состоит в том, что сгенерированный код должен быть красивым на вид, без предупреждений (неиспользуемый импорт и т. д.), как и остальная часть вашего кода.Так много сгенерированного кода неприятно читать... это ужасно.
В любом случае, документации не так много, но я думаю, что API довольно простой/интуитивный.Репозиторий Maven здесь если кому интересно.
Я сам делал это для инструмента-генератора макетов.Это очень простая задача, даже если вам нужно следовать рекомендациям Sun по форматированию.Могу поспорить, что вы закончите код, который делает это, быстрее, чем найдете в Интернете что-то, соответствующее вашей цели.
По сути, вы сами описали API.Просто заполните его реальным кодом прямо сейчас!
А также есть СтрокаШаблон.Он создан автором ANTLR и является довольно мощным.
Есть новый проект напиши это один раз.Генератор кода на основе шаблонов.Вы пишете собственный шаблон, используя классный, и генерировать файл в зависимости от отражений 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.
Пример: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//"));
Вот проект JSON-to-POJO, который выглядит интересно: