Реализация сгенерированного интерфейса с JavaPoet - PullRequest
1 голос
/ 13 марта 2020

Я хотел бы использовать JavaPoet для создания интерфейса и класса, реализующего этот интерфейс.

TypeSpec if = TypeSpec.interfaceBuilder("MyInterface")
                      .build();

TypeSpec cl = TypeSpec.classBuilder("MyClass")
                      .build();

Но я изо всех сил говорю JavaPoet, что MyClass должен реализовать MyInterface. Метод addSuperinterface(TypeName) требует имя типа, и я не нашел, как превратить TypeSpec в TypeName. Единственный способ, который я нашел, это позвонить ClassName#get(String, String).

Есть ли лучший способ добиться этого и напрямую использовать спецификацию типа для интерфейса?

1 Ответ

1 голос
/ 13 марта 2020

Это не так сложно, как может показаться. TypeSpe c .Builder имеет две версии метода addSuperInterface:

TypeSpec.Builder    addSuperinterface(Type superinterface) 
TypeSpec.Builder    addSuperinterface(TypeName superinterface)

Мы можем использовать вторую версию, например, и получить суперинтерфейс как экземпляр класса TypeName, используя ClassName.get

Одна из сигнатур метода get класса ClassName:

public static ClassName get(String packageName, String simpleName, String... simpleNames)

Таким образом, мы могли бы использовать его с пустой строкой для имени пакета, так как вы не указали имя пакета в своем интерфейсе спе c. Это будет работать, потому что ClassName extends TypeName. С другой стороны, мы можем получить простое имя интерфейса, используя свойство name типа spe c.

Вот полный пример реализации. Я изменил имя переменных (имя переменной , если , который вы использовали для интерфейса spe c, не будет работать, так как это ключевое слово java).

@Data
public class SimpleClassSpecs {

    public final TypeSpec interfaceSpec;
    public final TypeSpec classSpec;

    public SimpleClassSpecs() {
        interfaceSpec = TypeSpec.interfaceBuilder("MyInterface")
                .build();

        TypeName interfaceTypeName = ClassName.get("", interfaceSpec.name);
        classSpec = TypeSpec.classBuilder("MyClass")
                .addSuperinterface(interfaceTypeName)
                .build();
    }
}

Я использовал Lombok @ Data для стандартного кода (геттеры и сеттеры ...). Вот соответствующий тест (утверждение написано assertj):

@Test
public void should_generate_spec_with_superInterface() {
   SimpleClassSpecs ps = new SimpleClassSpecs();
   assertThat(ps.classSpec.toString()).contains("class MyClass implements MyInterface");
}

Или просто выполнив System.out.println(ps.classSpec), можно получить следующий результат:

class MyClass implements MyInterface {
}
...