it-swarm-eu.dev

Java API pro generování zdrojových souborů Java

Hledám rámec pro generování zdrojových souborů Java.

Něco jako následující API:

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

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

Pak by měl být zdrojový soubor Java nalezen v podadresáři cílového adresáře.

Ví někdo takový rámec?


UPRAVIT:

  1. Opravdu potřebuji zdrojové soubory.
  2. Také bych chtěl vyplnit kód metod.
  3. Hledám abstrakci na vysoké úrovni, ne přímou manipulaci/generování bytecode.
  4. Potřebuji také "strukturu třídy" ve stromu objektů.
  5. Problémová doména je obecná: generovat velké množství velmi odlišných tříd bez „společné struktury“.

SOLUTIONS
Zaslal jsem 2 odpovědi na základě vašich odpovědí ... s CodeModel a s Eclipse JDT .

Použil jsem CodeModel v mém řešení :-)

123
Daniel Fanjul

Sun poskytuje rozhraní API nazvané CodeModel pro generování zdrojových souborů jazyka Java pomocí rozhraní API. Není to nejjednodušší získat informace, ale je to tam a funguje to velmi dobře.

Nejjednodušší způsob, jak toho dosáhnout, je součástí JAXB 2 RI - generátor schématu XJC-to-Java používá CodeModel pro generování svého zdroje Java a je to součást sklenic XJC. Můžete jej použít pouze pro CodeModel.

Chyť to z http://codemodel.Java.net/

69
skaffman

Řešení nalezené v CodeModel
Díky, skaffman .

Například s tímto kódem:

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

Můžu dostat tento výstup:

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

Řešení nalezené s Eclipse JDT je ​​AST
Díky, Giles .

Například s tímto kódem:

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

Můžu dostat tento výstup:

package foo;
import Java.util.Set;
class Foo<X> {
  void MISSING(){
    x();
  }
}
27
Daniel Fanjul

K vytváření kódu můžete použít Roaster ( https://github.com/forge/roaster ).

Zde je příklad: 

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

zobrazí následující výstup:

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

Další alternativou je Eclipse JDT AST, což je dobré, pokud potřebujete přepsat libovolný zdrojový kód Java a ne pouze generovat zdrojový kód. (A věřím, že jej lze použít nezávisle na Eclipse).

9
Squirrel

Projekt Eclipse JET může být použit pro generování zdroje. Nemyslím si, že je to API, jako je ten, který jste popsali, ale pokaždé, když jsem slyšel o projektu, který generuje zdroj Java, použili JET nebo domácí nástroj.

4
Mike Deck

Nevíte o knihovně, ale generický šablony engine může být vše, co potřebujete. Jsou spousta z nich , osobně jsem měl dobré zkušenosti s FreeMarker

3
ykaganovich

Postavil jsem něco, co vypadá velmi podobně jako vaše teoretické DSL, nazvané "sourcegen", ale technicky místo projektu projektu pro ORM, který jsem napsal. DSL vypadá takto:

@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

To také dělá některé elegantní věci, jako je "Auto-organizovat importy" jakékoli FQCNs v parametrech/návratové typy, auto-prořezávání všechny staré soubory, které nebyly dotek v tomto běhu kodenu, správně odsazování vnitřní třídy, atd.

Myšlenka je, že vygenerovaný kód by měl být hezký, aby se na něj mohl podívat, bez varování (nevyužitý import atd.), Stejně jako zbytek kódu. Tolik vygenerovaný kód je ošklivý číst ... je to hrozné.

Mimochodem, není mnoho dokumentů, ale myslím, že API je velmi jednoduché/intuitivní. Reál Maven je zde pokud má někdo zájem.

2
Stephen Haberman

Pokud opravdu potřebujete zdroj, nevím nic, co by generovalo zdroj. Můžete však použít ASM nebo CGLIB k přímému vytvoření souborů .class. 

Ty by mohly být schopny generovat zdroj z nich, ale použil jsem je pouze ke generování bytecode.

1
Steve g

Existuje nový projekt write-it-once . Generátor kódu založený na šabloně. Vlastní šablonu píšete pomocí Groovy a generujete soubor v závislosti na odrazech Java. Je to nejjednodušší způsob jak vytvořit jakýkoliv soubor. Můžete vytvořit getters/settest/toString vytvořením souborů AspectJ, SQL na základě anotací JPA, vložek/aktualizací založených na enums a tak dále.

Příklad šablony:

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

K dispozici je také StringTemplate . Je to autor ANTLR a je poměrně silný.

1
Bala

Dělal jsem to sám pro falešný generátorový nástroj. Je to velmi jednoduchý úkol, i když potřebujete postupovat podle pokynů pro formátování Sun. Vsadím se, že jste dokončili kód, který to dělá rychleji, než jste našli něco, co vyhovuje vašemu cíli na internetu.

API jste v podstatě popsali sami. Stačí vyplnit aktuální kód!

1
Vladimir Dyuzhev

To opravdu záleží na tom, co se snažíte udělat. Generování kódu je téma samo o sobě. Bez konkrétního případu použití doporučuji podívat se na generování kódu rychlosti/šablonu. Také, pokud děláte generování kódu v režimu offline, doporučil bych použít něco jako ArgoUML pro přechod z UML diagramu/objektového modelu do kódu Java.

0
Berlin Brown

Příklad: 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//"));
0
user3207181

Zde je projekt JSON-to-POJO, který vypadá zajímavě:

http://www.jsonschema2pojo.org/

0
mtyson