Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics Error: inconvertible types from command line compiler

I have some Guice binding code using generics that compiles and functions fine from Eclipse's compiler, but not from the Java (command-line) compiler. I upgraded to the latest (1.7.0_01) Java SDK but still get the following error.

[error] ...\BindCategorySelectorActivity.java:42: error: inconvertible types
[error]                                 (Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>) CategoryDataProvider.class);
[error]                                                                                                                             ^
[error]   required: Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>
[error]   found:    Class<CategoryDataProvider>
[error] 1 error
[error] {file:/.../compile:compile: javac returned nonzero exit code

Relevant code:

public interface Category extends DatabaseItem {}
public class CategoryDataProvider implements 
 ListAdapterDataProvider<Row<Category>> {}
public class BindListViewHandlerWithSpecificProvider extends AbstractModule {
    public BindListViewHandlerWithSpecificProvider(
     Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>
      dataProviderClass) {}
}

@SuppressWarnings("unchecked")
// Error happens here:
final BindListViewHandlerWithSpecificProvider 
 bindListViewHandlerWithSpecificProvider = 
  new BindListViewHandlerWithSpecificProvider(
   (Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>)
    CategoryDataProvider.class);
like image 319
Jeff Axelrod Avatar asked Nov 14 '11 19:11

Jeff Axelrod


Video Answer


2 Answers

Do yourself a favor and do an upcast followed by a downcast:

Class<...> foo = (Class<...>)(Object)MyClass.class;

The issue is that CDP.class is of type Class<CDP>, CDP being a raw type. While a parameterized type C<T1,...,Tn> is the subtype of the raw type C (§4.10.2), the inverse is not true: C is not a subtype of C<T1,...,Tn>. This only appears to be true due to unchecked conversion (§5.1.9). This is causing your issue: You expect CDP to "extend" (as in the upper bound of Class<? extends ...>) LADP<Row<? extends DI>>. This is not the case because type argument containment (§4.5.1.1) is defined over subtyping and does not consider unchecked conversion.

(Or to cut to the chase: javac has got this one right.)

like image 77
Ben Schulz Avatar answered Sep 22 '22 15:09

Ben Schulz


I know the answer is working and accepted but I believe the downcast is not the perfect solution. Also my code cleanup remove the obsolete down cast...

1) the reason eclipse and command line does not yield the same problem is because of eclipse settings. Go to preferences - java - compiler - Errors/Warnings and set Generic types (unchecked generic type operation) to warning. Then you will detect the same problem if you remove the @SuppressWarnings("unchecked")

2) I had a similar issue and a friend show me another solution. To fix the code properly (without the down cast) just change the CategoryDataProvider.class to this:

new CategoryDataProvider<Row<DatabaseItem>>().getClass()

Then put back the @SuppressWarnings("unchecked")

like image 43
Martin P. Avatar answered Sep 19 '22 15:09

Martin P.