Java kaynak dosyaları oluşturmak için bir Java API [kapalı]


127

Java kaynak dosyaları oluşturmak için bir çerçeve arıyorum.

Aşağıdaki API gibi bir şey:

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

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

Ardından, hedef dizinin bir alt dizininde bir java kaynak dosyası bulunmalıdır.

Böyle bir çerçeve bilen var mı?


DÜZENLEME :

  1. Kaynak dosyalarına gerçekten ihtiyacım var.
  2. Ayrıca yöntemlerin kodunu da doldurmak istiyorum.
  3. Doğrudan bayt kodu işleme / oluşturma değil, yüksek düzeyde bir soyutlama arıyorum.
  4. Ayrıca bir nesneler ağacındaki "sınıfın yapısı" na da ihtiyacım var.
  5. Sorun alanı geneldir: "ortak bir yapı" olmadan çok sayıda çok farklı sınıf oluşturmak.

ÇÖZÜMLER
Yanıtlarınıza göre CodeModel ve Eclipse JDT ile 2 yanıt gönderdim .

Çözümümde CodeModel kullandım :-)


Sorunuz çok genel, sorun etki alanınız gerçekten bu kadar genel mi? Sorunlu alanınız hakkında daha spesifik olabilir misiniz? Örneğin, yinelenen istisna sınıfı kodunu ortadan kaldırmak veya numaralandırmalardaki yinelemeyi ortadan kaldırmak gibi belirli sorunlar için kod oluşturmak için kod oluşturma araçları yazdım.
Greg Mattes

@Vlookward: Soruya verdiğiniz cevapları aşağıdaki 2 ayrı cevap olarak taşıyabilirsiniz. Ardından Soru'dan her birine bir bağlantı ekleyin.
Ande Turner

@Banengusk: Sorduğun için teşekkürler, beni internetin en karanlık kısımlarını aramaktan saatler kurtardı. @skaffman: Harika keşif - yaklaşan göreviyle başka bir geliştiriciyi daha rahat hale getirdiniz :)
Ran Biron

Bu SO yanıtı, Java yerine C ++ sorusuna yöneliktir, ancak yanıt Java için de geçerlidir. stackoverflow.com/a/28103779/120163
Ira Baxter

Yanıtlar:


70

Sun, API kullanarak Java kaynak dosyaları oluşturmak için CodeModel adlı bir API sağlar. Hakkında bilgi almak için en kolay şey değil ama orada ve son derece iyi çalışıyor.

Bunu elde etmenin en kolay yolu JAXB 2 RI'nin bir parçasıdır - XJC şemadan java oluşturucu, java kaynağını oluşturmak için CodeModel kullanır ve XJC kavanozlarının bir parçasıdır. Bunu sadece CodeModel için kullanabilirsiniz.

Onu tut http://codemodel.java.net/


2
Tam ihtiyacım olan şey bu! Basit ve tamamen işlevsel. Teşekkürler skaffman!
Daniel Fanjul


@ykaganovich İyi çağrı. [ Repo.maven.apache.org/maven2/com/sun/codemodel/… CDDL ve GPL altında lisanslıdır). Önceki yorumumu kaldırdım.
Brad Cupit

46

CodeModel ile çözüm bulundu
Teşekkürler skaffman .

Örneğin, bu kodla:

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

Bu çıktıyı alabilirim:

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

Bu harika görünüyor. CodeModel ile üretilen başka bir türü döndüren bir yöntemi nasıl oluşturursunuz?
András Hummer


@ AndrásHummer cm._class(...), dönüş türü bağımsız değişkeni olarak döndürülen örneği kullanır dc.method(...).
Hugo Baés

28

Eclipse JDT'nin AST'si
sayesinde çözüm bulundu Teşekkürler Giles .

Örneğin, bu kodla:

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

Bu çıktıyı alabilirim:

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

Sorabilir miyim - bunu bir Java Eclipse Eklentisinin parçası olarak mı yaptınız yoksa bunu bağımsız kod olarak kullanmayı başardınız mı? Bunun yaşında olduğunun farkındayım.
mtrc

@mtrc İyi hatırlıyorsam, tutulma sırasında bağımsız ve normal bir java projesiydi, sınıf yoluna uygun kavanozu ekliyordu - ancak dosya adını hatırlamıyorum.
Daniel Fanjul

17

Kod oluşturmak için Roaster'ı ( https://github.com/forge/roaster ) kullanabilirsiniz.

İşte bir örnek:

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

aşağıdaki çıktıyı gösterecektir:

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

9

Diğer bir alternatif ise Eclipse JDT'nin AST'sidir; bu, yalnızca kaynak kodu oluşturmak yerine rasgele Java kaynak kodunu yeniden yazmanız gerekiyorsa iyidir. (ve tutulmadan bağımsız olarak kullanılabileceğine inanıyorum).


1
Harika!! Aradığım Özet Bir Sözdizimi Ağacı ... Şimdi API hakkında daha fazla bilgi arayacağım ... Teşekkürler !, :-)
Daniel Fanjul

API, beklediğim gibi karmaşıktır. Ama ihtiyacım olan tüm işlevselliğe sahip. Teşekkürler Giles.
Daniel Fanjul

1
@Gastaldi'de belirtildiği gibi, kavurma (JBoss Forge'dan) Eclipse JDT için güzel bir paketleyicidir. JDT'nin karmaşıklığını gizler ve java kodunu ayrıştırmak, değiştirmek veya yazmak için güzel bir API sağlar. github.com/forge/roaster
Jmini

4

Eclipse JET proje kaynak nesil yapmak için kullanılabilir. API'nin tam olarak tanımladığınız gibi olduğunu düşünmüyorum, ancak Java kaynak oluşturma yapan bir proje duyduğumda, JET veya kendi geliştirdiği bir araç kullanıyorlar.



2

Teorik DSL'inize çok benzeyen, "sourcegen" adında bir şey geliştirdim, ancak teknik olarak yazdığım bir ORM için bir kullanım projesi yerine. DSL şuna benzer:

@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

Ayrıca, parametreler / dönüş türlerindeki herhangi bir FQCN'yi "otomatik olarak düzenleyerek içe aktarır", bu kod oluşturucu çalıştırmasında dokunulmayan tüm eski dosyaları otomatik olarak budamak, iç sınıfları doğru şekilde girintilemek, vb. Gibi bazı düzgün şeyler de yapar.

Buradaki fikir, üretilen kodun, kodunuzun geri kalanı gibi hiçbir uyarı olmadan (kullanılmayan içe aktarmalar vb.) Güzel görünmesi gerektiğidir. Üretilen kodların çoğu okunması çirkin ... bu korkunç.

Her neyse, çok fazla belge yok, ancak API'nin oldukça basit / sezgisel olduğunu düşünüyorum. İlgilenen varsa Maven deposu burada .


1

Kaynağa GERÇEKTEN ihtiyacınız varsa, kaynağı oluşturan hiçbir şey bilmiyorum. .Class dosyalarını doğrudan oluşturmak için ASM veya CGLIB kullanabilirsiniz .

Bunlardan kaynak üretebilirsiniz, ancak bunları yalnızca bayt kodu oluşturmak için kullandım.


1

Sahte bir jeneratör aracı için kendim yapıyordum. Sun biçimlendirme yönergelerine uymanız gerekse bile bu çok basit bir görev. Bahse girerim kodu daha hızlı bitirirsiniz, sonra internette hedefinize uygun bir şey bulursunuz.

Temel olarak API'yi kendiniz belirlediniz. Şimdi gerçek kodla doldurun!


Hehehe ... Herhangi bir çerçeve bulunmazsa ben onu yazacağım. Çok fazla işlevsellik isterim, bu yüzden bir sabah
almayacağım


1

Bir kereliğine yazılan yeni bir proje var . Şablon tabanlı kod üreteci. Groovy kullanarak özel şablon yazarsınız ve java yansımalarına bağlı olarak dosya oluşturursunuz. Herhangi bir dosya oluşturmanın en basit yolu. AspectJ dosyaları, JPA açıklamalarına dayalı SQL, numaralandırmalara dayalı eklemeler / güncellemeler vb. Oluşturarak alıcılar / settest / toString yapabilirsiniz.

Şablon örneği:

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

0

Gerçekten ne yapmaya çalıştığınıza bağlı. Kod üretimi kendi içinde bir konudur. Belirli bir kullanım durumu olmadan, hız kodu oluşturma / şablon kitaplığına bakmanızı öneririm. Ayrıca, kod üretimini çevrimdışı yapıyorsanız, UML diyagramından / Nesne modelinden Java koduna gitmek için ArgoUML gibi bir şey kullanmanızı öneririm.


0

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.