Java 소스 파일을 생성하는 Java API


127

Java 소스 파일을 생성하는 프레임 워크를 찾고 있습니다.

다음 API와 같은 것 :

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

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

그런 다음 대상 디렉토리의 서브 디렉토리에서 Java 소스 파일을 찾아야합니다.

누구나 그런 프레임 워크를 알고 있습니까?


편집 :

  1. 정말 소스 파일이 필요합니다.
  2. 또한 메소드의 코드를 작성하고 싶습니다.
  3. 직접적인 바이트 코드 조작 / 생성이 아닌 높은 수준의 추상화를 찾고 있습니다.
  4. 또한 객체 트리에서 "클래스의 구조"가 필요합니다.
  5. 문제 영역은 일반적입니다. "공통 구조"없이 많은 다른 클래스를 생성하는 것입니다.

솔루션
나는 귀하의 답변을 기반으로 2 개의 답변을 게시했습니다 ... CodeModelEclipse JDT .

내 솔루션에서 CodeModel 을 사용 했습니다 :-)


귀하의 질문은 매우 일반적이며, 문제 영역은 정말 일반적인 것입니까? 문제 영역에 대해 더 구체적으로 설명 할 수 있습니까? 예를 들어 중복 예외 클래스 코드를 제거하거나 열거 형에서 중복을 제거하는 것과 같은 특정 문제에 대한 코드를 생성하는 코드 생성 도구를 작성했습니다.
Greg Mattes

@Vlookward : 질문에 배치 한 답변을 아래의 두 가지 답변으로 이동할 수 있습니다. 그런 다음 질문에서 각각에 대한 링크를 추가하십시오.
Ande Turner

@ Banengusk : 물어 주셔서 감사합니다, 인터넷의 가장 어두운 부분을 검색하는 시간을 절약했습니다. @skaffman : 위대한 찾기 - 당신이 :) 그의 곧 작업과 안심 다른 개발자 더 만든
곤 란

이 SO 답변은 Java가 아닌 C ++에 대한 질문을 해결하지만 Java에도 적용됩니다. stackoverflow.com/a/28103779/120163
Ira Baxter

답변:


70

Sun은 API를 사용하여 Java 소스 파일을 생성하기 위해 CodeModel이라는 API를 제공합니다. 정보를 얻는 것이 가장 쉬운 것은 아니지만 거기에 있으며 매우 잘 작동합니다.

그것을 잡는 가장 쉬운 방법은 JAXB 2 RI의 일부입니다. XJC schema-to-java 생성기는 CodeModel을 사용하여 Java 소스를 생성하며 XJC jar의 일부입니다. CodeModel에만 사용할 수 있습니다.

http://codemodel.java.net/ 에서 가져옵니다 .


2
그것은 내가 필요한 것입니다! 간단하고 완전한 기능. 고마워, skaffman!
Daniel Fanjul


@ykaganovich 잘 했어. [ repo.maven.apache.org/maven2/com/sun/codemodel/… CDDL 및 GPL에 따라 라이센스가 부여됨 )입니다. 이전 의견을 삭제했습니다.
Brad Cupit

46

CodeModel
Thanks, skaffman으로 해결책을 찾았습니다 .

예를 들어이 코드를 사용하면

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

이 출력을 얻을 수 있습니다 :

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

대단해 보인다. CodeModel로 생성되는 다른 유형을 반환하는 메서드는 어떻게 생성합니까?
András Hummer


@ AndrásHummer는에서 반환 된 인스턴스를에서 cm._class(...)반환 유형 인수로 사용합니다 dc.method(...).
Hugo Baés

28

Eclipse JDT의 AST
Thanks, Giles 에서 해결책을 찾았습니다 .

예를 들어이 코드를 사용하면

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

이 출력을 얻을 수 있습니다 :

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

물어볼 수 있습니까-Java Eclipse 플러그인의 일부로 이것을 했습니까? 아니면 독립형 코드로 사용하셨습니까? 나는 이것이 오래되었다는 것을 알고 있습니다.
mtrc 2016 년

@mtrc 만약 내가 잘 기억한다면, 이클립스에서 독립적이고 일반적인 자바 프로젝트 였고, 클래스 패스에 적절한 jar를 추가했지만 파일 이름을 기억하지 못한다.
Daniel Fanjul

17

Roaster ( https://github.com/forge/roaster )를 사용 하여 코드 생성을 수행 할 수 있습니다 .

예를 들면 다음과 같습니다.

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

다음과 같은 출력이 표시됩니다.

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

9

또 다른 대안은 Eclipse JDT의 AST입니다. 소스 코드를 생성하는 대신 임의의 Java 소스 코드를 다시 작성해야하는 경우에 좋습니다. (그리고 나는 일식과 독립적으로 사용할 수 있다고 생각합니다).


1
큰!! 추상 구문 트리는 내가 찾고있는 것입니다 ... 이제 API에 대한 자세한 정보를 검색 할 것입니다 ... Thanks !, :-)
Daniel Fanjul

예상대로 API는 복잡합니다. 그러나 필요한 모든 기능이 있습니다. 고마워, 길스
Daniel Fanjul

1
@gastaldi가 언급 한 것처럼, 로스터 (JBoss Forge)는 Eclipse JDT를위한 훌륭한 래퍼입니다. JDT의 복잡성을 숨기고 Java 코드를 구문 분석, 수정 또는 작성할 수있는 훌륭한 API를 제공합니다. github.com/forge/roaster
Jmini

4

이클립스 제트 프로젝트는 소스 생성을 수행하는 데 사용할 수 있습니다. 나는 그것이 API라고 생각하는 것과 정확히 같지는 않지만 Java 소스 생성을 수행하는 프로젝트를 들었을 때마다 JET 또는 자체 개발 도구를 사용했습니다.



2

나는 "sourcegen"이라는 이론적 인 DSL과 매우 유사한 것을 만들었지 만 기술적으로 필자가 작성한 ORM에 대한 util 프로젝트 대신에 그것을 만들었습니다. DSL은 다음과 같습니다.

@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

또한 매개 변수 / 반환 유형의 FQCN을 "자동 가져 오기 가져 오기",이 codegen 실행에서 만지지 않은 오래된 파일을 자동 정리, 내부 클래스를 올바르게 들여 쓰기 등의 깔끔한 작업을 수행합니다.

아이디어는 생성 된 코드가 코드의 나머지 부분과 마찬가지로 경고 (사용하지 않은 가져 오기 등)없이 잘보아야한다는 것입니다. 너무 많이 생성 된 코드는보기에 못 생겼습니다 ... 끔찍 해요.

어쨌든 많은 문서는 없지만 API는 매우 간단하고 직관적이라고 생각합니다. 관심이 있다면 Maven 저장소가 여기에 있습니다 .


1

당신이 소스를 정말로 필요로한다면, 나는 소스를 생성하는 것을 모른다. 그러나 ASM 또는 CGLIB 를 사용하여 .class 파일을 직접 작성할 수 있습니다.

이것들로부터 소스를 생성 할 수도 있지만 바이트 코드를 생성하는 데만 사용했습니다.


1

모의 생성기 도구를 위해 직접하고있었습니다. Sun 포맷 지침을 따라야하는 경우에도 매우 간단한 작업입니다. 더 빠른 코드를 완성하고 인터넷에서 목표에 맞는 것을 찾았을 것입니다.

기본적으로 API를 직접 설명했습니다. 실제 코드로 채우십시오!


Hehehe ... 만약 프레임 워크가 없다면 나는 그것을 쓸 것이다. 나는 많은 기능을 원하므로 아침에 그것을 얻지 못할 것입니다 ...
Daniel Fanjul


1

새로운 프로젝트 write-it-once가 있습니다. 템플릿 기반 코드 생성기. Groovy를 사용하여 사용자 정의 템플리트를 작성 하고 Java 리플렉션에 따라 파일을 생성합니다. 파일을 생성하는 가장 간단한 방법입니다. AspectJ 파일, JPA 주석 기반 SQL, 열거 형 기반 삽입 / 업데이트 등을 생성하여 getters / settest / toString을 작성할 수 있습니다.

템플릿 예 :

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

실제로 당신이하려는 일에 달려 있습니다. 코드 생성은 그 자체의 주제입니다. 특정 유스 케이스가 없으면 속도 코드 생성 / 템플릿 라이브러리를 살펴 보는 것이 좋습니다. 또한 코드 생성을 오프라인으로 수행하는 경우 ArgoUML과 같은 것을 사용하여 UML 다이어그램 / 객체 모델에서 Java 코드로 이동하는 것이 좋습니다.


0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.