-2

I faced this issue and hence posting it as complete solution -

With Java 8, the below code will fail with Runtime exception. The problem is getInteger method is returning a generic Integer type and print method expects exact Object Type.

public static void main(String[] args) {
    print(getInteger());
}

private static <T> T getInteger() {
    return (T)new Integer(10);
}

private static void  print(Object...o1){
    for(Object o: o1){
       System.out.println(o);
    }
}
Mohammad Adnan
  • 6,527
  • 6
  • 29
  • 47
  • 2
    I do not understand, why would you cast an Integer to T? – jontro Feb 24 '15 at 09:43
  • 1
    I tried your code in Java 8. It works perfectly. What do you mean with "likely to fail" anyway? Did you even try it yourself? – David ten Hove Feb 24 '15 at 09:44
  • 2
    I think it might be better if you posted it as an actual question and then gave the solutions as an answer, then accept it. – ChiefTwoPencils Feb 24 '15 at 09:44
  • *"is likely to fail"*?? Did you try it really? It works perfrectly under java 8. Furthermore, *"I hope it will help"* - great! Thank you very much for helping us! – Andremoniy Feb 24 '15 at 09:45
  • 1
    @Andremoniy It fail at runtime with a `ClassCastException: java.lang.Integer cannot be cast to [Ljava.lang.Object;` – Marko Topolnik Feb 24 '15 at 09:51
  • @DavidtenHove Try to run it once. it will fail at Runtime as i mentioned. Not sure what else u need. – Mohammad Adnan Feb 24 '15 at 09:52
  • 1
    Whilst it's good to [answer your own question](http://stackoverflow.com/help/self-answer), the preferred way is to separate the problem that is being solved from the solution into individual question and answer components. You can then accept your own answer. – Edd Feb 24 '15 at 09:52
  • 1
    @MohdAdnan I did run it. More than once. The output was 10 every time. No exceptions whatsoever. – David ten Hove Feb 24 '15 at 09:52
  • @DavidtenHove check if u r using jre 8. – Mohammad Adnan Feb 24 '15 at 09:56
  • @MarkoTopolnik oh, really? I can not reproduce it – Andremoniy Feb 24 '15 at 09:58
  • 1
    I'm using the JDK, not the JRE. It's version 1.8.0-b132 – David ten Hove Feb 24 '15 at 09:58
  • JRE is a part of JDK, so in runtime it uses same one. @MohdAdnan should provide us his OS version and JRE version – Andremoniy Feb 24 '15 at 09:59
  • @Andremoniy Are you positively sure that you are using version 8 source level? Although the problem is manifested at runtime, it is actually independent of the JRE version. – Marko Topolnik Feb 24 '15 at 10:00
  • Its Windows 7 profession with jre1.8.0_31. @DavidtenHove dear I atleast expect you know what is jre and jdk. I seriously think that u r not using java 8. – Mohammad Adnan Feb 24 '15 at 10:02
  • 1
    My java -version output: java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode) – David ten Hove Feb 24 '15 at 10:04
  • @MarkoTopolnik yes, I'm positvely shure. Win7 64, JDK 1.8.0_31 – Andremoniy Feb 24 '15 at 10:09
  • @Andremoniy And you tried it with plain `javac Test.java`? Or better yet, with `javac -source 8 Test.java`? – Marko Topolnik Feb 24 '15 at 10:11
  • @DavidtenHove Please try to compile and run ur program using this javac -source 8 Test.java and check your path and java_home if it is set properly to java 8 – Mohammad Adnan Feb 24 '15 at 10:21
  • Ok so something really weird is going on. I added some Java 8 specific code (Stream stuff and method references) to the main method to make sure I use Java 8. In Eclipse, it compiles and runs just fine. But when I compile it from the command line, I do get the error. So the reason I do not get the error in Eclipse does not have to do with Java 8 itself, Eclipse just compiles it differently. But for the life of me, I can't figure out the difference between Eclipse compiling it in Java 8 or just me doing it from the command line... Anybody have any idea? – David ten Hove Feb 24 '15 at 10:35
  • And yes, I did check things like project settings and execution environments. – David ten Hove Feb 24 '15 at 10:35
  • 1
    @DavidtenHove Eclipse has its own, independently developed compiler with its own set of bugs. In this particular case the bug may work in OP's favor, but the code should actually fail *by specification*. `javac` is the reference implementation of a fully JLS-compliant compiler. – Marko Topolnik Feb 24 '15 at 11:22
  • 1
    @MarkoTopolnik in that case, this question deserves my upvote. – David ten Hove Feb 24 '15 at 11:45

2 Answers2

9

Your code mixes type inference with varargs.

In Java 7, it worked because there was no target type inference: the type of getInteger call was resolved as just Object, and then the object was boxed into an Object[] to fit the varargs call.

With Java 8, T is inferred from the target type as Object[]. Since you perform an unchecked cast in getInteger, this is completely valid, and mandated by the method signature resolution rules, which will consider varargs only if resolution failed without considering it. Here, that was not the case.

Lesson: by performing the unchecked type cast you have waived your right to expect type safety and correctness. You should be prepared to take care of it yourself.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
-1

As part of solution choose any of the following.

Break method call and argument pass in two calls –

Integer i = getInteger();

print(i);

Or

Call print method with Typed argument –

  print(Main.<Integer>getInteger());

I hope it will help.

Mohammad Adnan
  • 6,527
  • 6
  • 29
  • 47
  • 1
    No, there is only one correct solution: remove the nonsensical type argument `T` from `getInteger()`. – Holger Feb 24 '15 at 11:07
  • 2
    That's subjective. but what if u have that code in API and has hundreds of usages. sometimes we just need to go with flow @Holger – Mohammad Adnan Feb 24 '15 at 11:50
  • That’s hilarious, you proposed “solution” **is** to fix the place where it is used, so **you** are proposing to fix every of the hundred call sites instead of fixing the one broken method. And, by the way, changing the return type to what the method really returns will not break any call site that wasn’t already broken. – Holger Feb 24 '15 at 12:05
  • Yes because every hundred site is doing it wrong. They are passing different type (e.g Integer here) where as method expects different type (e.g. Object here). Java 7 has bug that doesn't gave error for this. In Java 8 they fixed it and it start showing run time error. regardless of whether you use type casting or not it will fail if u try to call a method with different types. did u understand problem at first place? – Mohammad Adnan Feb 24 '15 at 12:22
  • 2
    Just declare a method that returns `Integer` to return `Integer` and there will be no problem at all. There is no reason to insert a meaningless type parameter here. The only call-sites which will stop working then are call-sites which substituted `T` for a type that is incompatible with the `Integer` type, in other words, only broken call-site can’t be compiled then. But if you prefer code that throws at runtime, well, I hope I never have to deal with code from you. – Holger Feb 24 '15 at 12:33
  • 1
    This just an example there could be cases where u have to pass a type. thats why generic is made. For me it is not everytime Integer but it could be any type. anyway I m trying last time to explain the problem just read this https://bugs.openjdk.java.net/browse/JDK-8072919 – Mohammad Adnan Feb 24 '15 at 13:10
  • 1
    The report you have linked is closed as being “Not an Issue”. For exactly [the same reason; it’s not a bug when broken code shows wrong behavior](https://bugs.openjdk.java.net/browse/JDK-8072919?focusedCommentId=13608415&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13608415). You should read what you link. And no, there are *no* legit use cases for generic methods claiming to return whatever the caller wishes. – Holger Feb 24 '15 at 13:18
  • @Holger I don't think you are trying to understand what I am telling u. offcourse it is not an issue in java 8. Java 7 has an issue that it DOESN'T report such error. Anyways thanks a lot of commenting. take care. – Mohammad Adnan Feb 24 '15 at 13:26
  • No, that’s definitely wrong Java 7, *does* give you an *unchecked* warning at the broken method. And since the *method* is broken, the *method* has to be fixed. Your proposal is to fix the caller and that’s simply wrong, regardless of whether you are using Java 7 or Java 8. And there is no real use case for the method to be generic anyway, again, regardless of whether you are using Java 7 or Java 8. The runtime exception you get now is just a symptom of the problem that even Java 5 warns you about. – Holger Feb 24 '15 at 13:32
  • 1
    I don't disagree that we should be type safe and avoid such casting. There is no question/argument regarding this. This solution will work for people who can not change such method as it is exposed by third party (or something) and can change their own code to work. – Mohammad Adnan Feb 24 '15 at 13:53