-
Enhancement
-
Resolution: Not an Issue
-
P4
-
None
-
6u10
-
x86
-
windows_xp
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
(this is not an OS specific issue)
EXTRA RELEVANT SYSTEM CONFIGURATION :
n/a
(this is not a configuration specific issue)
A DESCRIPTION OF THE PROBLEM :
If a class that has optional generic types is instantiated using the raw type... all return types for methods throughout that class are stripped, and now return raw types.
Related bugs:
5073043
5074427
6545698
The problem is not as simple as the solution addressed in these discarded bugs. The problem is one of passivity. If a class has a method with a typesafe construct in the return type, no generic type can EVER add to that class, for it will be break any consumers of that existing method that rely on the typesafety.
This seems like a pretty large burden to put on developers.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a basic class.
2. Create a method within that class that returns a parametrized generic type. (e.g. Collection<String>)
3. Use that method in a way that depends on that return type. (e.g. String s = col.get(0))
4. Verify everything compiles.
5. Add a generic to the basic class declaration. (e.g. <T>)
6. A compiler error is now generated on the line of code from step 3.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would not expect a raw type returned from a method that does not depend on the class' generic type. (i.e. Obviously a method returning type T would be stripped, but if it's returning an explicit type, there is no reason to strip it.)
ACTUAL -
Class does not compile.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
GenericsBug.java:28: incompatible types
found : java.lang.Object
required: java.lang.Number
Number n2 = new Generic().getGenericNumbers().get(0);
^
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.*;
public class GenericsBug
{
public static void main(String[] args)
{
//Simple class without generics that has a method that returns a type-safe list
class NoGeneric
{
public List<Number> getGenericNumbers()
{
return new ArrayList<Number>();
}
}
//This compiles fine, as the typesafe list returns a Number
Number n1 = new NoGeneric().getGenericNumbers().get(0);
//Simple class with a generic type that has the EXACT SAME method as above that returns a type-safe list
class Generic<T>
{
public List<Number> getGenericNumbers()
{
return new ArrayList<Number>();
}
}
//This does not compile, because getGenericNumbers() is now returning a raw List,
//simply because the generic not being declared with a type
Number n2 = new Generic().getGenericNumbers().get(0);
//This DOES compile, because types are not stripped
//This is the recommended solution from previous bugs, but we can't
//break existing consumers of our class, meaning we can't add generics at all
Number n3 = new Generic<Object>().getGenericNumbers().get(0);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only workaround is not exposing typesafe objects as return types, and forcing the consumers to infer the cast (effectively preventing the use of generics all together) until we can declare that the class will never have a generic type.
For classes and packages without unknown consumers, simply adding the unchecked 'cast' resolves the compiler error.
e.g.
Number n2 = ((List<Number>)new Generic().getGenericNumbers()).get(0);
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
(this is not an OS specific issue)
EXTRA RELEVANT SYSTEM CONFIGURATION :
n/a
(this is not a configuration specific issue)
A DESCRIPTION OF THE PROBLEM :
If a class that has optional generic types is instantiated using the raw type... all return types for methods throughout that class are stripped, and now return raw types.
Related bugs:
5073043
5074427
6545698
The problem is not as simple as the solution addressed in these discarded bugs. The problem is one of passivity. If a class has a method with a typesafe construct in the return type, no generic type can EVER add to that class, for it will be break any consumers of that existing method that rely on the typesafety.
This seems like a pretty large burden to put on developers.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a basic class.
2. Create a method within that class that returns a parametrized generic type. (e.g. Collection<String>)
3. Use that method in a way that depends on that return type. (e.g. String s = col.get(0))
4. Verify everything compiles.
5. Add a generic to the basic class declaration. (e.g. <T>)
6. A compiler error is now generated on the line of code from step 3.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would not expect a raw type returned from a method that does not depend on the class' generic type. (i.e. Obviously a method returning type T would be stripped, but if it's returning an explicit type, there is no reason to strip it.)
ACTUAL -
Class does not compile.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
GenericsBug.java:28: incompatible types
found : java.lang.Object
required: java.lang.Number
Number n2 = new Generic().getGenericNumbers().get(0);
^
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.*;
public class GenericsBug
{
public static void main(String[] args)
{
//Simple class without generics that has a method that returns a type-safe list
class NoGeneric
{
public List<Number> getGenericNumbers()
{
return new ArrayList<Number>();
}
}
//This compiles fine, as the typesafe list returns a Number
Number n1 = new NoGeneric().getGenericNumbers().get(0);
//Simple class with a generic type that has the EXACT SAME method as above that returns a type-safe list
class Generic<T>
{
public List<Number> getGenericNumbers()
{
return new ArrayList<Number>();
}
}
//This does not compile, because getGenericNumbers() is now returning a raw List,
//simply because the generic not being declared with a type
Number n2 = new Generic().getGenericNumbers().get(0);
//This DOES compile, because types are not stripped
//This is the recommended solution from previous bugs, but we can't
//break existing consumers of our class, meaning we can't add generics at all
Number n3 = new Generic<Object>().getGenericNumbers().get(0);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only workaround is not exposing typesafe objects as return types, and forcing the consumers to infer the cast (effectively preventing the use of generics all together) until we can declare that the class will never have a generic type.
For classes and packages without unknown consumers, simply adding the unchecked 'cast' resolves the compiler error.
e.g.
Number n2 = ((List<Number>)new Generic().getGenericNumbers()).get(0);
- relates to
-
JDK-5073043 Generic class vs Foreach causes compile error
-
- Closed
-
-
JDK-5074427 Foreach seeing wrong parameterized return type
-
- Closed
-
-
JDK-6545698 Erroneous method typing for parametrized inner class methods in foreach syntax.
-
- Closed
-
-
JDK-6817013 Iterative for loop fails to find generics information of cast classes
-
- Closed
-