Sebastien Diot Sebastien Diot - 2 months ago 14x
Java Question

How to handle generics inside a Java "annotation processor"?

I asked before for an example "annotation processor" that would generate a Proxy/Delegate for an interface, but got no answer, and did not find anything on the Internet, so I made my own.

So far it worked well, until I tried to use generics inside a super-interface. If I use generics in the annotated interface, it works fine (more by accident than by design). But if the annotated interface extends another interface that takes a generic type parameter, that parameter is not "bound" to the type that the annotated interface use when extending the super-interface. Example:

public interface TestFragment<E> {
void test(E dummy);
public interface TestService extends TestFragment<String> {
double myOwnMethod();

This would generate:

// ...
public void test(final E dummy) {
// ...

instead of the correct:

// ...
public void test(final String dummy) {
// ...

The code that generates the parameters in the generated methods look like this:

int count = 0;
for (VariableElement param : method.getParameters()) {
if (count > 0) {
pw.print(", ");
pw.printf("final %s %s", param.asType().toString(),

Is there a way to do this?


What you need is substitution, given a map of type variables to type arguments. In this case, E->String. Replace any E in any type with String

There is no such support in javax.lang.model.util.Types, you need to roll your own. Basically

void print(TypeMirror type, Map<TypeVariable,TypeMirror> substitution)

    if(substitution.containsKey(type)) // type is a var, E
        print( substitution.get(type) ); // String

    else if(type instanceof DeclaredType) // e.g. List<E>
        print( type.asElement().getSimpleName() );  // List
        for(TypeMirror arg : type.getTypeArguments() ) // E
            print(arg, substitution)

    etc. something like that