Domanda

Sto cercando un framework per generare file sorgente Java.

Qualcosa come la seguente API:

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

File targetDir = ...;
clazz.generate(targetDir);

Quindi, un file sorgente Java dovrebbe essere trovato in una sottodirectory della directory di destinazione.

Qualcuno conosce un tale framework?


Modifica :

  1. Ho davvero bisogno dei file sorgente.
  2. Vorrei anche compilare il codice dei metodi.
  3. Sto cercando un'astrazione di alto livello, non diretta manipolazione / generazione di bytecode.
  4. Ho anche bisogno della struttura "quot della classe" in un albero di oggetti.
  5. Il dominio problematico è generale: generare una grande quantità di classi molto diverse, senza una "struttura comune".

SOLUZIONI
Ho pubblicato 2 risposte in base alle tue risposte ... con CodeModel e ??con Eclipse JDT .

Ho usato CodeModel nella mia soluzione, :-)

È stato utile?

Soluzione

Sun fornisce un'API chiamata CodeModel per la generazione di file di origine Java mediante un'API. Non è la cosa più semplice per ottenere informazioni, ma è lì e funziona estremamente bene.

Il modo più semplice per ottenerlo è come parte del RI JAXB 2: il generatore da schema a java XJC utilizza CodeModel per generare la sua fonte java ed è parte dei barattoli XJC. Puoi usarlo solo per CodeModel.

Prendilo da http://codemodel.java.net/

Altri suggerimenti

Soluzione trovata con CodeModel
Grazie, skaffman .

Ad esempio, con questo codice:

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

Posso ottenere questo output:

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

Soluzione trovata con AST di Eclipse JDT
Grazie, Giles .

Ad esempio, con questo codice:

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

Posso ottenere questo output:

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

Puoi usare Roaster ( https://github.com/forge/roaster ) per generare codice.

Ecco un esempio:

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

visualizzerà il seguente output:

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

Un'altra alternativa è l'AST di JDT di Eclipse, che è utile se è necessario riscrivere il codice sorgente Java arbitrario piuttosto che generare semplicemente il codice sorgente. (e credo che possa essere usato indipendentemente dall'eclissi).

Il progetto Eclipse JET può essere utilizzato per generare la fonte. Non credo che l'API sia esattamente come quella che hai descritto, ma ogni volta che ho sentito parlare di un progetto che sta generando sorgenti Java hanno usato JET o uno strumento di produzione nazionale.

Non conosci una libreria, ma un motore di template generico potrebbe essere tutto ciò di cui hai bisogno. Ci sono alcuni di essi , personalmente ho avuto una buona esperienza con FreeMarker

Ho creato qualcosa che assomiglia molto al tuo DSL teorico, chiamato "sourcegen", ma tecnicamente invece di un progetto util per un ORM che ho scritto. Il DSL assomiglia a:

@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

Fa anche cose ordinate come " Organizza automaticamente le importazioni " eventuali FQCN nei parametri / tipi restituiti, eliminazione automatica di tutti i vecchi file che non sono stati toccati in questa esecuzione di codegen, rientro corretto delle classi interne, ecc.

L'idea è che il codice generato dovrebbe essere carino da guardare, senza avvisi (importazioni inutilizzate, ecc.), proprio come il resto del codice. Tanto codice generato è brutto da leggere ... è orribile.

Comunque, non ci sono molti documenti, ma penso che l'API sia piuttosto semplice / intuitiva. Il repository Maven è qui se qualcuno è interessato.

Se hai davvero bisogno della fonte, non so nulla che generi fonte. Puoi tuttavia utilizzare ASM o CGLIB per creare direttamente i file .class.

Potresti essere in grado di generare sorgente da questi, ma li ho usati solo per generare bytecode.

Lo stavo facendo da solo per uno strumento generatore di finto. È un compito molto semplice, anche se è necessario seguire le linee guida sulla formattazione di Sun. Scommetto che finiresti il ??codice che lo fa più velocemente, poi hai trovato qualcosa che si adatta al tuo obiettivo su Internet.

Fondamentalmente hai delineato l'API da solo. Basta riempirlo con il codice attuale ora!

Esiste anche StringTemplate . È dell'autore di ANTLR ed è abbastanza potente.

Esiste un nuovo progetto write-it-once . Generatore di codice basato su template. Scrivi un modello personalizzato usando Groovy e generi file a seconda delle riflessioni Java. È il modo più semplice per generare qualsiasi file. Puoi creare getter / settest / toString generando file AspectJ, SQL basato su annotazioni JPA, inserimenti / aggiornamenti basati su enum e così via.

Esempio di modello:

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

Dipende davvero da cosa stai cercando di fare. La generazione del codice è un argomento in sé. Senza un caso d'uso specifico, suggerisco di esaminare la libreria di generazione / modello di codice di velocità. Inoltre, se stai eseguendo la generazione del codice offline, ti suggerirei di usare qualcosa come ArgoUML per passare dal diagramma UML / modello di oggetti al codice Java.

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

Ecco un progetto da JSON a POJO che sembra interessante:

http://www.jsonschema2pojo.org/

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top