Una API Java para generar archivos fuente Java

Estoy buscando un marco para generar archivos fuente de Java.

Algo así como la siguiente API:

X clazz = Something.createClass("package name", "class name"); clazz.addSuperInterface("interface name"); clazz.addMethod("method name", returnType, argumentTypes, ...); File targetDir = ...; clazz.generate(targetDir); 

Luego, se debe encontrar un archivo fuente java en un subdirectorio del directorio de destino.

¿Alguien conoce ese marco?


EDITAR :

  1. Realmente necesito los archivos fuente.
  2. También me gustaría completar el código de los métodos.
  3. Estoy buscando una abstracción de alto nivel, no manipulación / generación de bytecode directa.
  4. También necesito la “estructura de la clase” en un árbol de objetos.
  5. El dominio del problema es general: generar una gran cantidad de clases muy diferentes, sin una “estructura común”.

SOLUCIONES
He publicado 2 respuestas basadas en tus respuestas … con CodeModel y con Eclipse JDT .

He utilizado CodeModel en mi solución, 🙂

Sun proporciona una API llamada CodeModel para generar archivos fuente Java utilizando una API. No es lo más fácil obtener información, pero está allí y funciona extremadamente bien.

La forma más fácil de conseguirlo es como parte de JAXB 2 RI: el generador XJC de esquema a java utiliza CodeModel para generar su fuente java, y es parte de los archivos JJJ. Puede usarlo solo para CodeModel.

Cógelo de http://codemodel.java.net/

Solución encontrada con CodeModel
Gracias, skaffman .

Por ejemplo, con este código:

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

Puedo obtener esta salida:

 package foo; public class Bar { int foo() { return 5; } } 

Solución encontrada con AST de Eclipse JDT
Gracias, Giles .

Por ejemplo, con este código:

 AST ast = AST.newAST(AST.JLS3); ComstacktionUnit cu = ast.newComstacktionUnit(); 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); 

Puedo obtener esta salida:

 package foo; import java.util.Set; class Foo { void MISSING(){ x(); } } 

Puede usar Roaster ( https://github.com/forge/roaster ) para generar código.

Aquí hay un ejemplo:

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

mostrará el siguiente resultado:

 public class MyClass { private String testMethod() { return null; } } 

Otra alternativa es el AST de Eclipse JDT, que es bueno si necesita reescribir el código fuente de Java arbitrario en lugar de solo generar el código fuente. (y creo que se puede usar independientemente del eclipse).

El proyecto Eclipse JET se puede usar para generar fonts. No creo que su API sea exactamente como la que describió, pero cada vez que oigo hablar de un proyecto con generación de fuente Java, han utilizado JET o una herramienta de cosecha propia.

No conozco una biblioteca, pero un motor de plantilla genérico puede ser todo lo que necesita. Hay muchos de ellos , personalmente he tenido una buena experiencia con FreeMarker

Construí algo que se parece mucho a su DSL teórico, llamado “sourcegen”, pero técnicamente en lugar de un proyecto de utilidad para un ORM que escribí. El DSL se ve así:

 @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

También hace algunas cosas interesantes como “organizar automáticamente las importaciones” cualquier FQCN en parámetros / tipos de retorno, podando automáticamente cualquier archivo antiguo que no se haya tocado en este codegen, mellando correctamente las clases internas, etc.

La idea es que el código generado sea bonito para mirarlo, sin advertencias (importaciones no utilizadas, etc.), al igual que el rest de tu código. Tanto código generado es feo de leer … es horrible.

De todos modos, no hay muchos documentos, pero creo que la API es bastante simple / intuitiva. El informe de Maven está aquí si alguien está interesado.

Si REALMENTE necesita la fuente, no sé de nada que genere la fuente. Sin embargo, puede usar ASM o CGLIB para crear directamente los archivos .class.

Es posible que pueda generar una fuente a partir de estos, pero solo los he usado para generar bytecode.

Lo estaba haciendo yo mismo para una herramienta de simulacro de generador. Es una tarea muy simple, incluso si necesita seguir las pautas de formato de Sun. Apuesto a que terminarás el código que lo hace más rápido y luego encontrarás algo que se adapte a tu objective en Internet.

Básicamente ha descrito la API usted mismo. ¡Solo complétalo con el código real ahora!

También hay StringTemplate . Es por el autor de ANTLR y es bastante poderoso.

Hay un nuevo proyecto write-it-once . Generador de código basado en plantillas. Usted escribe una plantilla personalizada usando Groovy y genera un archivo según las reflexiones de Java. Es la forma más sencilla de generar cualquier archivo. Puede crear getters / settest / toString generando archivos AspectJ, SQL basado en anotaciones JPA, inserciones / actualizaciones basadas en enumeraciones, etc.

Ejemplo de plantilla:

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

Realmente depende de lo que estás tratando de hacer. La generación de código es un tema en sí mismo. Sin un caso de uso específico, sugiero consultar la generación de código de velocidad / biblioteca de plantillas. Además, si está haciendo la generación de código fuera de línea, le sugiero que use algo como ArgoUML para pasar del diagtwig UML / modelo de objetos al código de Java.

Ejemplo: 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 DIT 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//")); 

Aquí hay un proyecto de JSON a POJO que se ve interesante:

http://www.jsonschema2pojo.org/