Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sun JDK 1.5 cannot dereference error with generics

We have a class hierarchy similar to this one:

public class TestDereference {
 private static MainInterface mi = new MainInterfaceImpl();

 public static void main(String[] args) {
  System.out.println(mi.getSubInterface().getField());
 }
}

interface MainInterface {
 <T extends SubInterface> T getSubInterface();
}

interface SubInterface {
 Field getField();
}

class Field {
 @Override
 public String toString() {
  return "Hooray!";
 }
}

class SubInterfaceImpl implements SubInterface {
 Field f = new Field();

 public Field getField() {
  return f;
 }

}

class MainInterfaceImpl implements MainInterface {
 SubInterfaceImpl si = new SubInterfaceImpl();

 public <T extends SubInterface> T getSubInterface() {
  return (T) si;
 }
}

The interfaces actually have more than one implementation but that's not the problem. Compiling this with the Eclipse compiler or Java 1.6 works just fine (as seen on ideone). But if I try to compile this with Java 1.5 (which is one of the requirements of our project) gives the following error:

TestDereference.java:12: test.SubInterface cannot be dereferenced
                System.out.println(mi.getSubInterface().getField());
                                                     ^

Also note that it doesn't happen with JDK 1.6 using -target 1.5 either, only with JDK 1.5

The only cases when this error occurs that I found on the web are related to doing things like this:

double d = 2.0;
d.toString();

where it's obvious what the problem is.

But it my case it should work, since it's clear that getSubInterface() returns a SubInterface implementing class that definitely has the getField() method.

So is this a compiler bug? And what options do I have besides doing mi.<SubInterface>getSubInterface() every single time (which works, but since Eclipse doesn't mark this as an error, most people on the team forget do it, and most of them use only JDK 1.6 so they don't notice it when compiling with maven/cmd line either)?

like image 425
Andrei Fierbinteanu Avatar asked Nov 10 '10 12:11

Andrei Fierbinteanu


2 Answers

Check bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5003431

Option one:

SubInterface si = mi.getSubInterface();
si.getField();

Option two:

mi.<SubInterface>getSubInterface().getField()
like image 190
dacwe Avatar answered Sep 30 '22 19:09

dacwe


I guess this is a bug that was fixed in Java6.

Rewriting your main method as follows will make things work in both Java5 and 6:

public static void main(String[] args) {
    SubInterface subInterface = mi.getSubInterface();
    System.out.println(subInterface.getField());
}

It seems Java5 needs the assignment to properly derive the type T, even though it's already declared to extends SubInterface. Java6 handles this correctly and doesn't need the additional assignment.

like image 42
Luke Hutteman Avatar answered Sep 30 '22 18:09

Luke Hutteman