Victor Mezrin
Victor Mezrin

Reputation: 2847

Java generics, get Class<T> of generic parameter

I have an abstract class:

public abstract class RootProcessor<T> {
    Class<T> clazz;
}

I need to fill ClassT clazz; with the children of RootProcessor - every child has its own T

I found only one solution, but it needs compiler argument -Xlint:unchecked

public RootProcessor(){
    this.clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

Is this the best solution? Can we do the same without -Xlint:unchecked ?

Upvotes: 53

Views: 109417

Answers (3)

LagSeeing
LagSeeing

Reputation: 73

As above you should use @SuppressWarnings.

But I'd like to use TypeToken in guava.

It can resolve generic type in inheritance.

package com.example.demo;

import com.google.common.reflect.TypeToken;

class A<A, B> {

}

class B<T> extends A<T, String> {

}

class C extends B<Long> {
}

public class Main {

    public static void main(final String[] args) {
        final var cTypeToken = TypeToken.of(C.class);
        final TypeToken<? super C> aTypeToken = cTypeToken.getSupertype(A.class);
        final TypeToken<?> resolved = aTypeToken.resolveType(A.class.getTypeParameters()[0]);
        // java.lang.Long
        System.out.println(resolved);
    }

}

Upvotes: 0

Basilios Raptis
Basilios Raptis

Reputation: 31

There is a post of the same subject: Reflecting generics

And a class that implement it:TypeArgumentsUtils.java

An example is in the unit test.

So if you have this class:

public class BarProcessor extends RootProcessor<Bar> {
    public BarProcessor() {
    }
}

than you would get the first parameter with:

Class barClass = TypeArgumentsUtils.getFirstTypeArgument(
        RootProcessor.class, BarProcessor.class);

Upvotes: 3

millimoose
millimoose

Reputation: 39950

The typesafe, but boilerplatey way to do this is to pass the Class<T> token "where the compiler can see it":

public abstract class RootProcessor<T> {
    Class<T> clazz;

    protected RootProcessor<T>(Class<T> clazz) {
        this.clazz = clazz;
    }
}

public class FooProcessor extends RootProcessor<Foo> {
    public FooProcessor() {
        super(Foo.class);
    }
}

If you're doing an unchecked cast but you "know what you're doing" and want the compiler to stop complaining, the correct approach would be localising the non-type-safe-but-you-know-they-work bits and using @SuppressWarnings:

public abstract class RootProcessor<T> {
    Class<T> clazz;
    { initClazz(); }

    @SuppressWarnings("unchecked")
    private void initClazz() {
        // the usual verbiage you already have in your question
        this.clazz = this.getClass().getGenericSuperclass().yadda().blah();
    }
}

(I won't hold this against you :P)

Upvotes: 40

Related Questions