JavaPoet - запись вызова статического универсального метода

Я хочу написать CodeBlock который в основном вызывает статический универсальный метод, но вывод, который я получаю с JavaPoet генерирует ошибки компилятора.

Например, задан следующий класс значений auto:

@AutoValue
public abstract class Test<T> {
    public abstract Test1<String> o();
    public abstract T p();

    @AutoValue
    public static abstract class Test1<T> {
        public abstract T value();

        public static <T> Test1<T> create(T value) {
            return Test1.<T>builder()
                    .value(value)
                    .build();
        }

        public static <T> Builder<T> builder() {
            return new AutoValue_ValueWithOperator.Builder<>();
        }

        public static <T> Builder<T> testBuilder() {
            return builder();
        }

        @AutoValue.Builder
        public abstract static class Builder<T> {
            public abstract Builder<T> value(T value);

            public abstract Test1<T> build();
        }
    }
}

Теперь скажите, что я хотел сгенерировать этот вызов testBuilder за Test1<String> (внутри теста), я сначала получаю TypeName при выполнении:

TypeName elementReturnType = TypeName.get(someTypeMirror);

Теперь, когда я делаю:

CodeBlock.of("$T.testBuilder()" + ".build()", elementReturnType);

Он генерирует код, который выглядит следующим образом:

Test.Test1<String>.testBuilder().build();

Это неправильно, правильный синтаксис должен быть:

Test.Test1.<String>testBuilder().build();

Обратите внимание на размещение универсального параметра... Как я могу сделать это с JavaPoet? У меня есть правильный тип, как вы можете видеть по сгенерированному коду, но он просто поместил универсальный параметр в неправильном месте.

У меня вопрос, как мне добавить общие параметры для вызова метода с помощью JavaPoet CodeBlock?

1 ответ

Вы просто должны заметить, что универсальный тип является частью метода, а не класса, поэтому, когда вы пишете вызов метода, попробуйте связать универсальный с той частью, где вы пишете вызов метода.

TypeName elementReturnType = TypeName.get(elementTypeMirror);

Предполагая, что у вас есть элемент, представляющий метод для вызова:

ExecutableElement method = ...;

if (methodElement.getTypeParameters().isEmpty()) {
    return CodeBlock.of("$T.$N().build()", elementReturnType, methodElement.getSimpleName());
}

String typeParams = MoreTypes
    .asDeclared(returnType)
    .getTypeArguments()
    .stream()
    .map(MoreTypes::asTypeElement)
    .map(TypeElement::getQualifiedName)
    .collect(Collectors.joining("<", ",", ">");

Это даст вам параметры типа, которые вы можете прикрепить к названию имени метода (method.getSimpleName()).

Другие вопросы по тегам