2008-09-23 13 views
121

Estoy buscando un marco para generar archivos fuente Java.Una API Java para generar archivos fuente Java

algo como lo 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); 

A continuación, un archivo fuente de Java se debe encontrar en un subdirectorio del directorio de destino.

¿Alguien conoce este tipo de marco?


EDITAR:

  1. que realmente necesitan los archivos de origen.
  2. También me gustaría completar el código de los métodos.
  3. Estoy buscando una abstracción de alto nivel, no una 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
me han publicado 2 respuestas basadas en sus respuestas ... with CodeModel y with Eclipse JDT.

he utilizado en mi CodeModel solución, :-)

+0

Su pregunta es muy general, ¿su dominio de problemas es realmente este general? ¿Puedes ser más específico sobre tu dominio problemático? Por ejemplo, he escrito herramientas de generación de código para generar código para problemas específicos, como eliminar el código de clase de excepción duplicada o eliminar la duplicación en enumeraciones. –

+0

@Vlookward: puede mover las respuestas que ha colocado en la Pregunta como 2 respuestas separadas a continuación. Luego agregue un enlace a cada uno de la Pregunta. –

+0

Oh, sí. Buena idea. –

Respuesta

68

Sun proporciona una API llamada CodeModel para generar archivos fuente de 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 de esquema XJC a java utiliza CodeModel para generar su fuente Java, y es parte de los archivos JJJ. Puede usarlo solo para CodeModel.

Grab desde http://codemodel.java.net/

+2

¡Es justo lo que necesito! Simple y completamente funcional. Gracias, skaffman! –

+1

@BradCupit De acuerdo con el archivo pom http://repo.maven.apache.org/maven2/com/sun/codemodel/codemodel/2.6/codemodel-2.6.pom, es CDDL + GPL https://glassfish.java .net/public/CDDL + GPL_1_1.html – ykaganovich

+0

@ykaganovich Buena llamada. Es [http://repo.maven.apache.org/maven2/com/sun/codemodel/codemodel-project/2.6/codemodel-project-2.6.pom](dual con licencia bajo CDDL y GPL). Eliminé mi comentario anterior. –

1

Si realmente necesita la fuente, que no sé nada de lo que genera 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.

+0

Realmente necesito los archivos fuente. ¡Gracias! –

4

El proyecto Eclipse JET se puede utilizar para generar fuentes. 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.

1

Lo estaba haciendo yo mismo para una herramienta de simulacro 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 objetivo en Internet.

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

+0

Hehehe ... Si no se encuentra un marco, entonces voy a escribirlo. Me gustaría tener muchas funcionalidades, así que no lo conseguiré en la mañana ... –

9

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

+1

¡¡Genial !! Un árbol de sintaxis abstracto es lo que estoy buscando ... Ahora buscaré más información sobre la API ... ¡Gracias! :-) –

+0

La API es compleja, como esperaba. Pero tiene toda la funcionalidad que necesito. Gracias, Giles. –

+1

Como lo menciona @gastaldi, el tostador (de JBoss Forge) es un buen envoltorio para Eclipse JDT. Oculta la complejidad de JDT y proporciona una buena API para analizar, modificar o escribir código Java. https://github.com/forge/roaster – Jmini

3

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

44

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 conseguir este resultado:

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

Esto se ve impresionante. ¿Cómo se genera un método que devuelve otro tipo que también se está generando con CodeModel? –

+0

@DrH, simple búsqueda en google: http://codemodel.java.net/nonav/apidocs/com/sun/codemodel/JDefinedClass.html#method(int,%20com.sun.codemodel.JType,%20java.lang. String) –

+0

@ AndrásHummer usa la instancia devuelta de 'cm._class (...)' como argumento de tipo de retorno para 'dc.method (...)'. –

27

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

Por ejemplo, con este código:

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

puedo conseguir este resultado:

package foo; 
import java.util.Set; 
class Foo<X> { 
    void MISSING(){ 
    x(); 
    } 
} 
+0

¿Puedo preguntar: ¿lo hizo como parte de un complemento de Java Eclipse o se las arregló para usar esto como código independiente? Me doy cuenta de que esto tiene años. – mtrc

+0

@mtrc Si mal no recuerdo, era un proyecto java independiente y normal en eclipse, que agregaba el jar apropiado al classpath, pero no recuerdo el nombre del archivo. –

+0

OK, muchas gracias por la ayuda! :) – mtrc

0

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 diagrama UML/modelo de objetos al código de Java.

2

He creado 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 "Auto-organización de las importaciones" ningún FQCNs en los parámetros/retorno tipos, auto-poda de los archivos antiguos que no fueron tocadas en este codegen run, correctamente sangrando clases internas, etc.

La idea es que el código generado debería ser bonito para mirarlo, sin advertencias (importaciones no utilizadas, etc.), al igual que el resto de su 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 es here si alguien está interesado.

+0

¡Muchas gracias! –

0

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 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//")); 
1

Hay nuevo proyecto write-it-once. Generador de código basado en plantillas.Usted escribe una plantilla personalizada usando Groovy, y genera un archivo dependiendo de 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 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; 
    } 
} 
16

Puede utilizar Asador (https://github.com/forge/roaster) para hacer la generación de código.

Aquí se muestra 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; 
    } 
} 
+0

¡eso es genial! –

Cuestiones relacionadas