Closed anilnf closed 8 years ago
That is probably due to changes in type inference in Java 8 (which for GWT relies on the java compiler library in eclipse JDT).
String.valueOf has many overloads and the call is quite ambiguous because the type parameter is only used in the return type. So some overload is selected and a cast to that parameter type is inserted due to type erasure (standard java).
Inserting a cast and rewriting to
String.valueOf((String) prop.get("yo");
or having a variable
String propValue = String.valueOf(...)
or making the type argument explicit
String.<String>valueOf(...)
should remove the ambiguity from the call.
This happens in run after build (as war) as well. Building with Java 8 as well as Java 7. Yes. The solutions you mentioned actually works.
On Mon 3 Oct, 2016, 9:36 PM rluble, notifications@github.com wrote:
That is probably due to changes in type inference in Java 8 (which for GWT relies on the java compiler library in eclipse JDT).
String.valueOf has many overloads and the call is quite ambiguous because the type parameter is only used in the return type. So some overload is selected and a cast to that parameter type is inserted due to type erasure (standard java).
Inserting a cast and rewriting to
String.valueOf((String) prop.get("yo");
or having a variable
String propValue = String.valueOf(...)
or making the type argument explicit
String.valueOf(...)
should remove the ambiguity from the call.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/gwtproject/gwt/issues/9439#issuecomment-251148563, or mute the thread https://github.com/notifications/unsubscribe-auth/AMMxWGpt40yijaLN1W2MCGR96kEiv_48ks5qwSgDgaJpZM4KMWEH .
FYI, GWT 2.8 always uses Java 8 mode independent of your IDE settings.
I've experimented the same behavior. I don't know if it should be considered an error but, in fact, in GWT 2.7.0 the same code works well but just changing to GWT 2.8 causes the ClassCastException has been fired:
public class Jee7 implements EntryPoint {
static class GenericElement {
public <VALUE> VALUE getValue() {
return (VALUE)"Hola";
}
}
public void test() {
String value = String.valueOf(new GenericElement().getValue());
Window.alert("value: " + value);
}
public void onModuleLoad() {
try {
test();
} catch (ClassCastException e) {
Window.alert("ClassCastException!");
}
}
}
Compiled with GWT 2.7.0
Compiled with GWT 2.8
I know that we can avoid the ClassCastException just by declaring explicitly the generic type or guiding the compiler type inference engine to the correct String.valueOf overloaded method. With this little change in the code, the error won't occur:
public void test() {
String value = String.valueOf(new GenericElement().<Object>getValue());
Window.alert("value: " + value);
}
But anyway, some code already tested and working in production environment compiled with GWT 2.7.0 could fail just compiling with the 2.8 version and, what is worse, in a silent way.
Should it be considered, in some way, a bug?
It's not a bug because you also get a ClassCastException when doing the same code in pure Java8 without any GWT involved, e.g.
public class Main {
static class GenericElement {
public <VALUE> VALUE getValue() {
return (VALUE)"Hola";
}
}
public static void main(String[] args) {
String value = String.valueOf(new GenericElement().getValue());
System.out.println("value: " + value);
}
}
The above code compiles in Java 8 but fails at runtime with:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to [C
at test.Main.main(Main.java:12)
Confirmed: https://ideone.com/1BoRrV (Java 8) vs. http://www.browxy.com/SubmittedCode/647675 (Java 7)
It is quite surprising that Java semantics don't flag this call as ambiguous or choose String.valueOf(Object) as the appropriate overload.
I totally agree @rluble
Java overload resolution chooses the most specific overload, and because you let it "choose" the generic type argument, it's "free" to choose the char[]
overload over the Object
one (actually no "free", but following the algorithms from the JLS, as both javac and jdt behave the same way)
On the bright side javac will warn you of the unsafe behavior of methods declared with a free type variable in the return type. To be able to construct a method with a free type variable in the return type you need to have an unsafe cast (unless you always return null).
I take this as an unwanted interaction between the "most specific overload rule" and "left-to-right" aspect of Java type inference. I wonder if the other sensible choice (applying the most specific overload rule based on the erasure of free type variables and then perform type inference) has also some unwanted interactions.
FWIW, Errorprone has a more descriptive warning for this scenario (http://errorprone.info/bugpattern/TypeParameterUnusedInFormals)
is there anyway to get warned about all the potential exceptions of this type in a gwt codebase ?
That is the reason it is not a good practice to declare a type variable that is only used on the return type. You can use errorprone to warn you about this one and other potential pitfalls.
Failure in 2.8RC2 jar: (Same code works in gwt2.7) CodeSnippet which failed (passes once we remove String.valueOf):
ClassCastException:
Throwable.java:121Uncaught Error: java.lang.ClassCastExceptionjjc_g$ @ Throwable.java:121tjc_g$ @ Throwable.java:113ajc_g$ @ Throwable.java:61Gjc_g$ @ Exception.java:25Ojc_g$ @ RuntimeException.java:25xpi_g$ @ ClassCastException.java:23xVj_g$ @ InternalPreconditions.java:141HVj_g$ @ InternalPreconditions.java:129tne_g$ @ Cast.java:75