Search code examples
javagenericstype-erasuretype-safetyraw-types

how to get generic type through .class?


The problematic code is shown below.

class GenericClass<T> {
    // ...
}

class RegisterHandler<T> {
    // ...
    public void register( Class<T> klazz ) {
        // do something
    }
    // ...
}

class GenericClassRegisterHandler extends RegisterHandler<GenericClass<?>> {
    // ...
}

public static void registerAll() {
    // ...
    new GenericClassRegisterHandler().register( GenericClass.class );
    // error: actual argument Class<GenericClass> cannot be converted to Class<GenericClass<?>> by method invocation conversion
    // ...
}

The only way was to use rawtypes, either by changing register to Class klazz instead of Class<T>, or by casting new GenericClassRegisterHandler() to (RegisterHandler)new GenericClassRegisterHandler(). Since both of these "fixes" exploit rawtypes and I don't want to use them (why should I? I should be able to get Class<GenericClass<?>> somehow by .class!), yet I see no other solution so far. Am I missing something obvious and it's possible without reifying wrappers etc, or is it just impossible?

Note: Wrapping a Class<?> type generics error is a nice & enlightening find, but doesn't work here.

Note 2: While Bloch in EJ 2nd is discussing similar problems, I were unable to find any explicit solution to this exact case.

BTW the obvious (Class<GenericClass<?>>) GenericClass.class doesn't work due to incompatible types: Class<GenericClass<?>> cannot be converted to Class<GenericClass>

Test snippet on http://ideone.com/Fr4yng


Solution

  • My solution was to do a double cast.

     new GenericClassRegisterHandler()
        .register( (Class<GenericClass<?>>) (Class<?>) GenericClass.class );
    

    While it's arguably not the most elegant one, in some situations (e.g. you're the producer, and the consumer's interface is set in stone, or you just don't want to change it for any other reason) it's the best one - because it's the only one possible.