53

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 ?

5
  • 5
    Don't use -Xlint:unchecked, use @SuppressWarnings as locally as possible if you need unsafe casts. Commented May 28, 2013 at 18:42
  • 4
    And, yeah, there is no way to get Class<T> safely at runtime if the compiler can't track the type of T from beginning to end. The typesafe but boilerplatey approach here is to simply introduce a protected constructor that takes clazz as a parameter. Commented May 28, 2013 at 18:44
  • @millimoose: Why don't you write that as an answer? I have very little to add to your comments ;-) Commented May 28, 2013 at 18:46
  • yes, its a great answer. I think constructor with a parameter is a great solution. Its simple answer for this question ))) Commented May 28, 2013 at 18:50
  • As an example: key = gson.fromJson(json, key.getClass().getGenericSuperclass()); fixes key = gson.fromJson(json,HashMap.class); Commented Mar 10, 2019 at 10:50

3 Answers 3

41

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)

Sign up to request clarification or add additional context in comments.

Comments

3

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);

2 Comments

Second link is broken.
1

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

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.