Szukam frameworka do generowania plików źródłowych Java.
Coś w rodzaju następującego interfejsu API:
X clazz = Something.createClass("package name", "class name");
clazz.addSuperInterface("interface name");
clazz.addMethod("method name", returnType, argumentTypes, ...);
File targetDir = ...;
clazz.generate(targetDir);
Następnie plik źródłowy Java powinien znajdować się w podkatalogu katalogu docelowego.
Czy ktoś zna takie ramy?
EDYCJA :
- Naprawdę potrzebuję plików źródłowych.
- Chciałbym również wypełnić kod metod.
- Szukam abstrakcji wysokiego poziomu, a nie bezpośredniej manipulacji / generowania kodu bajtowego.
- Potrzebuję również „struktury klasy” w drzewie obiektów.
- Dziedzina problemowa jest ogólna: generowanie dużej liczby bardzo różnych klas bez „wspólnej struktury”.
ROZWIĄZANIA
Opublikowałem 2 odpowiedzi oparte na twoich odpowiedziach ... z CodeModel i Eclipse JDT .
W swoim rozwiązaniu wykorzystałem CodeModel , :-)
java
eclipse
code-generation
Daniel Fanjul
źródło
źródło
Odpowiedzi:
Firma Sun udostępnia interfejs API o nazwie CodeModel do generowania plików źródłowych Java za pomocą interfejsu API. Nie jest to najłatwiejsza rzecz do uzyskania informacji, ale jest tam i działa bardzo dobrze.
Najłatwiej jest go zdobyć w ramach JAXB 2 RI - generator schematu XJC-to-java używa CodeModel do generowania źródła Java i jest on częścią jarów XJC. Możesz go użyć tylko dla CodeModel.
Pobierz go z http://codemodel.java.net/
źródło
Rozwiązanie znalezione z CodeModel
Thanks, skaffman .
Na przykład z tym kodem:
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);
Mogę uzyskać ten wynik:
package foo; public class Bar { int foo() { return 5; } }
źródło
cm._class(...)
jako argumentu typu zwracanego dladc.method(...)
.Rozwiązanie znalezione za pomocą programu AST Eclipse JDT
Thanks, Giles .
Na przykład z tym kodem:
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);
Mogę uzyskać ten wynik:
package foo; import java.util.Set; class Foo<X> { void MISSING(){ x(); } }
źródło
Możesz użyć Roaster ( https://github.com/forge/roaster ) do generowania kodu.
Oto przykład:
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);
wyświetli następujące dane wyjściowe:
public class MyClass { private String testMethod() { return null; } }
źródło
Inną alternatywą jest AST Eclipse JDT, który jest dobry, jeśli chcesz przepisać dowolny kod źródłowy Java, a nie tylko generować kod źródłowy. (i uważam, że można go używać niezależnie od zaćmienia).
źródło
Projekt Eclipse JET może służyć do generowania źródeł. Nie sądzę, żeby to API było dokładnie takie, jak to, które opisałeś, ale za każdym razem, gdy słyszałem o projekcie generującym źródła w Javie, używali JET lub własnego narzędzia.
źródło
Nie znasz biblioteki, ale może być wszystko, czego potrzebujesz, jeśli potrzebujesz ogólnego silnika szablonów. Jest ich sporo , osobiście miałem dobre doświadczenia z FreeMarkerem
źródło
Zbudowałem coś, co wygląda bardzo podobnie do twojego teoretycznego DSL, zwanego "sourcegen", ale technicznie zamiast projektu użytkowego dla ORM, który napisałem. DSL wygląda następująco:
@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
Wykonuje również kilka fajnych rzeczy, takich jak „Automatyczne organizowanie importu” wszelkich FQCN w parametrach / typach zwracanych, automatyczne przycinanie wszelkich starych plików, które nie zostały dotknięte w tym przebiegu kodegenu, prawidłowe wcięcie klas wewnętrznych itp.
Chodzi o to, że wygenerowany kod powinien wyglądać ładnie, bez ostrzeżeń (nieużywane importy itp.), Tak jak reszta kodu. Tak dużo wygenerowanego kodu jest brzydkie do odczytania ... to straszne.
W każdym razie nie ma wielu dokumentów, ale myślę, że API jest dość proste / intuicyjne. Repozytorium Maven jest tutaj, jeśli ktoś jest zainteresowany.
źródło
Jeśli NAPRAWDĘ potrzebujesz źródła, nie znam niczego, co je generuje. Możesz jednak użyć ASM lub CGLIB do bezpośredniego tworzenia plików .class.
Możesz być w stanie wygenerować z nich źródło, ale użyłem ich tylko do wygenerowania kodu bajtowego.
źródło
Robiłem to sam dla narzędzia do symulowanego generatora. To bardzo proste zadanie, nawet jeśli musisz przestrzegać wytycznych dotyczących formatowania firmy Sun. Założę się, że skończyłbyś kod, który robi to szybciej, niż znalazłeś w Internecie coś, co pasuje do twojego celu.
W zasadzie sam opisałeś API. Po prostu wypełnij go rzeczywistym kodem teraz!
źródło
Istnieje również StringTemplate . Jest autorstwa autora ANTLR i jest dość potężny.
źródło
Pojawił się nowy projekt jednorazowego zapisu . Generator kodu oparty na szablonach. Piszesz własny szablon za pomocą Groovy i generujesz plik w zależności od odbić Java. To najprostszy sposób na wygenerowanie dowolnego pliku. Możesz tworzyć getters / setest / toString, generując pliki AspectJ, SQL na podstawie adnotacji JPA, wstawki / aktualizacje na podstawie wyliczeń i tak dalej.
Przykład szablonu:
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; } }
źródło
To naprawdę zależy od tego, co próbujesz zrobić. Generowanie kodu jest tematem samym w sobie. Bez konkretnego przypadku użycia proponuję przyjrzeć się bibliotece szablonów / generowania kodu prędkości. Ponadto, jeśli generujesz kod offline, sugerowałbym użycie czegoś takiego jak ArgoUML, aby przejść od diagramu UML / modelu obiektowego do kodu Java.
źródło
Przykład: 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//"));
źródło
Oto projekt JSON-to-POJO, który wygląda interesująco:
http://www.jsonschema2pojo.org/
źródło