0

I want to write a CodeBlock which is basically calling a static generic method, but the output I get with JavaPoet is generating compiler errors.

For example given the following auto value class:

@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();
        }
    }
}

Now say I wanted to generate a that call to the testBuilder for Test1<String> (inside Test), I first obtain the TypeName by doing:

TypeName elementReturnType = TypeName.get(someTypeMirror);

Now when I do:

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

It generates code that looks like:

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

This is wrong, the correct syntax should be:

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

Note the placement of the generic parameter...How can I accomplish this with JavaPoet? I have the correct type as you can see by the generated code, but it's just placed the generic parameter in the wrong place.

My question is, how do I add generic parameters to method call using JavaPoet CodeBlock?

smac89
  • 39,374
  • 15
  • 132
  • 179

1 Answers1

0

You just have to note that the generic type is part of the method, not the class, so when you write your method call, try to associate the generic with the part where you write the method call.

TypeName elementReturnType = TypeName.get(elementTypeMirror);

Assuming you have an element representing the method to call:

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("<", ",", ">");

This will give you the type params which you can attach to the name of the name of the method (method.getSimpleName()).

smac89
  • 39,374
  • 15
  • 132
  • 179