ClassCastException should always report incompatible type - Java SE (Archived)

Default constructor should be deprecated and removed because it is useless: it does not provide information to resolve error.

+1
Sounds like a simple fix and I agree that ClassCastException with no description is difficult to fix.

Further, everytime a CCE is thrown, message like this should be provided:
java.lang.ClassCastException: whatever.pckg.OffendingClass incompatible with expected another.pckg.ExpectedClass
Reason is that if message contains only offending class, it may not be sufficient information to resolve such error if it occurs in third party library without any sources or debug info (line numbers at least). You just don't know what was expected...
This should not be so hard :-) In fact, taking this to extreme, CCE should have single constructor only:
public ClassCastException(Class expected, Class offending) {} // plus optionally variant with additional explanatory message
but this is just a hardcore solution :-)
Message was edited by: patrikbeno

+1

Related

How to unserialize parametrized types without compile-time warnings

I'm trying to serialize Hashset <Type> and Arraylist <type>. I can use stream.WriteObject to serialize them OK.
And stream.ReadObject reads the object OK. But I get a complie-time warning that
setmoveList = (ArrayList<Move>) (is.readObject());has an unchecked cast.
If I replace the code with
Object o= is.readObject();
if (o instanceof ArrayList<Move>) {
  SetMoveList=  (ArrayList<Move>) o
}I get a compile time error "illegal generic type for instanceof".
Obviously I can live with the warnings, but is there a way of producing clean code which checks the type correctly?
Edited by: ptoye on May 7, 2013 2:51 AM 
Your quest to write clean code is commendable, but it is very much subject to personal taste. For example: I find code that has suppress warning annotations on it clean enough, other people will ridicule me for it. What do you think?
is there a way of producing clean code which checks the type correctly?Reason about it for a moment: can you check the type correctly at compile time? readObject() is totally a runtime deal. 
I take your point about it being taste, and certainly wouldn't think of ridiculing you for your stance. I've been living with this particular issue for some months now.
But isn't "instanceof" a run-time check? I'd have expected that the runtime system would read in the object and then check its type against the required template. After all, it has to do this for simpler forms like ReadInt (and throw an exception if they're not correct). Or is it just too complex for parameterised types? I must try writing one type of Object and reading in another here to see what happens. 
ptoye wrote:
But isn't "instanceof" a run-time check? I'd have expected that the runtime system would read in the object and then check its type against the required template. After all, it has to do this for simpler forms like ReadInt (and throw an exception if they're not correct). Or is it just too complex for parameterised types? I must try writing one type of Object and reading in another here to see what happens.java generics are "erased" at runtime, thus "instanceof" has no meaning when it comes to generic parameters. the only way to fully verify that "List<String>" is valid is to call instanceof on every element of the List. 
>
java generics are "erased" at runtime, thus "instanceof" has no meaning when it comes to generic parameters. the only way to fully verify that "List<String>" is valid is to call instanceof on every element of the List.
OIC. Thanks.
Of course, this means that instead of serialising the entire structure I'd have to serialise each item separately and rebuild it part by part. Too much like hard work for no gain.

ErrorType bugfix

Previously on "Annotation Processing"...
Bruce Chapman wrote:
if our code is
class MyClass extends Gen<MySuperClass> {}
then the annotation processor cannot see the name of the superclass nor its type elements. I think this is a bug, because
http://java.sun.com/javase/6/docs/api/index.html?javax/lang/model/type/ErrorType.html
has a getTypeArguments() method, that ought to work in this case. Certainly that was my intent when we worked on that API.
I have patched the compiler to get this working, (small patch 5 lines added, 1 deleted - (# LOC/hr == 1) so we may need to proceed with a patched compiler until I can get the bug submitted, accepted, and rolled out. We have almost definitely missed the boat for JDK6 U2. I Still need to test my patch against compiler TCK.
So, did the changes get into the compiler, or rather are they going to?
I tried something like the above on 1.6.0_03 and it didn't seem to have the appropriate stuff in the ErrorType. In addition, it chucked out some horrid compiler error messages about the missing class, which are a bit off putting if the annotation processor is going to create the missing file as soon as it is given a chance.
Comments? 
class MyClass extends Gen<MySuperClass> {}
While on the subject, what is asElement() of the ErrorType supposed to return if Gen is underfined?
Currently it seems to return a class element for class "<any>" (Types.asElement() returns null).
Are you going to return a faked up TypeElement for the right name?
If not, where do we go to get "Gen", the name of the superclass? Should there be another method of ErrorType to get this?
Jonty
Edited by: jontyla on Nov 21, 2007 8:46 AM Corrected when null returned. 
In case anybody is just using the e-mailed versions of this forum, I edited the previous reply to correct an error in it. Most importantly I changed:
Currently it seems to return a class element for class "<any>" (Types.asElement() returns null). 
Jonty,
I think that has got stalled somewhere. I will investigate and follow up. I won't have any time for a few days tho. I could post my patch for javac? if you're happy working with that?
The ErrorType behaves correctly when the type is a "raw" identifier (since the compiler can't find it, all it knows about it is the identifier (name). The ErrorType currently loses the identifier if the type has type parameters. The patch I wrote makes an unknown type with type parameters work similar to a raw unknown type, and the type parameters will themselves be resolved to the actual types or to more error types if they are also unknown (latter case is unusual). 
Hi Bruce,
I could post my patch for javac? if you're happy working with that?I can test amost all of what I'm doing without it.
On the other hand, if you post the patch then when I get to it I could use it for the appropriate tests, and give you feedback if there were any problems. No hurry though.
Jonty

Type safety warning... what does it mean?

Hello guys.... and gals... using the Eclipse IDE and it is giving a warning to which I cannot fully understand... my code runs fine, but I don't like warnings and would like to understand and possibly fix it.
I am trying to clone a LinkedList object. The linked list contains a series of custom objects in this case called Card. Now when I wish to make a copy I am cloning the LinkList and casting it, which is resulting in this warning:
Type safety: The cast from Object to LinkedList <Card> is actually checking against the erased type LinkedList.
Here is the code:
LinkedList <Card> tempPile = (LinkedList <Card>) m_cards.clone();Any ideas? 
regarding the above I forgot to mention m_cards is a LinkedList <Card> though I'm sure most deduced that...
woah 79 views and no reply... suddenly I don't feel so stupid regarding this warning..
oh mighty and powerful Java God's shed some light on thee...
Message was edited by:
Kurisu_Dickens 
You need no god. You cast to a generic, which always will cause the warning you mentioned (it's about compile time type safety provided by Generics). The only thing you can do is to suppress the warning using SuppressWarnings appropriately. eclipse will assist you doing so. 
Reason:
Because [url http://java.sun.com/javase/6/docs/api/java/util/LinkedList.html#clone()]LinkedList.clone() method returns the Object type and that your code is casting its return reference to the generic type LinkedList<Card>.
This creates an unchecked warning.
To know more about this kind of warning read: [url http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Compiler%20Messages]Angelika Langer's Compiler Messages FAQ.
Remedy:
Add the annotation:#SuppressWarnings("unchecked")either above your method or your class with the warning.
-or-
In Eclipse set the compiler to ignore this kind of warning either in your current project:
(project Properties / Java Compiler / Errors/Warnings / Enable project specific settings / Generic types / Unchecked generic type operation / Ignore)
or in every project:
(menu Window / Preferences / Java / Compiler / Errors/Warnings / Generic types / Unchecked generic type operation / Ignore)
-or-
Learn to live with those warnings :-)
Regards 
Heheh I have no problem living with it... just wondered was all.. thanks for clarifying it for future reference.. definitely worth knowing.. you would think they would provide a better warning instead of how the worded it... your guys explaination was very straight forward and clear ....thanks....

Unchecked cast and ClassCastException handling

Hello,
I have just posted the following RFE to the bug database, and I would like to know what people in the community think of my idea. I'm waiting for your comments on this small but sometimes annoying issue.
Date Created: Wed Oct 25 22:36:08 MDT 2006
Type: rfe
status: Waiting
Category: java
Subcategory: compiler
Synopsis: Unchecked cast warning and ClassCastException handling
Description:
A DESCRIPTION OF THE REQUEST :
The java compiler should not issue an unchecked cast warning when the statement causing this warning is inside a try-catch block that explicitely handles ClassCastException.
JUSTIFICATION :
In many cases, such as when creating objects through reflection, it is not possible to write code that doesn't generate unchecked cast warnings. In these cases, the developper is well aware of the unchecked cast and wil have explicitely handled this case by catching ClassCastException and taking the appropriate action.
The ultimate goal behind compiler warnings is to bring possible problems forward to make sure the developper is aware of them. In this particular case, it is clear that the developper is already aware of the caveat and has taken the appropriate steps to handle it. Issuing a warning in this case is just superfluous.
On the otherhand, using the #SuppressWarnings annotation feels like "telling the compiler to shut up" while not really fixing the problem at all. It feels neither clean nor safe. Having to use this annotation feels like there is something wrong in the code, which is not necessarily the case.
Additionally since the #SuppressWarnings annotation can only be used on a class or method level, it might be dangerous to use. If a developper codes a method for which he cannot avoid the unchecked cast warning and then annotates the method with #SuppressWarnings, all the generics code that he will write later on in the same method will not be appropriately checked by the compiler, thus introducing the possibility of additional silenced unchecked cast warning which the developper might not be aware of.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
code such as:
Class<? extends MyObject> clazz = null;
try{
     clazz = (Class<? extends MyObject>)Class.forName(className);
}catch(ClassCastException cce){
     // handle the exception correctly
     log.warn("Invalid type");
     throw new SomeCheckedException();
}should compile without warning, since it is clear that the programmer is aware of the unchecked cast and has taken appropriate measures to protect himself against it.
               
ACTUAL -
The code above makes the compiler issue an unchecked cast warning. This forces the user to "tell the compiler to shut up" using the #SuppressWarnings anotation, which feels like a clunky, unsafe workaround.
CUSTOMER SUBMITTED WORKAROUND :
Use the #SuppressWarnings annotation. 
Additionally since the #SuppressWarnings annotation
can only be used on a class or method levelI'm pretty sure you are wrong there:
#Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) 
Hmm.. I've tried it on my own code and it seems not to generate an error message when used right before a local variable declaration. So you are right on this one.
However, using the annotation this way, I am unable to silence the warning... so it seems that while you can place it a local variable level, it makes it ineffective.
And the rest of my points still hold, I think. 
Hmm.. I've tried it on my own code and it seems not
to generate an error message when used right before a
local variable declaration. So you are right on this
one.
However, using the annotation this way, I am unable
to silence the warning... so it seems that while you
can place it a local variable level, it makes it
ineffective.Because putting SuppressWarning on a field will only suppress warnings in the expression being used to assign the field. 
The reason the warning is "unchecked" is that generic casts can't always verify that the object is really of the target type at the point the cast is done, so such a cast can result in the ClassCastException occuring later, which might well be outside your try block.
Suppose you have a List<Object> which contains, say, an Integer and you cast it to List<String> at the time of the cast the runtime can't verify that the list contains only strings. So, maybe much later, you do a get on the cast list you can get a ClassCastException on a line of code with no explicit cast. 
Hmm... That makes sense...
it seems that I posted and idiot RFE... Well, it seemed like a good idea at the time I posted it.

Downcast an object to a Map<key, value> causes warning, why?

Hi, thank you for reading this post!
Here is the code:
     HashMap<Person, BookEntry> phonebook1 = (HashMap<Person, BookEntry>)ois.readObject();Here is the compile-time warning, why? I did downcast from an Object to a HashMap<Person, BookEntry> with the
above code.
found   : java.lang.Object
required: java.util.HashMap<Person,BookEntry>
                                HashMap<Person, BookEntry> phonebook1 = (HashMap<Person, BookEntry>)
ois.readObject();
               ^
1 warningThanks in advance for your help!
Eric 
Well, I googled 'unchecked cast from object to hashmap' and from what I found it appears (guessing here) the implementation of generics in Java only checks one level deep for conformity. It doesnt actually check the cast to parameterized HashMap for example. I suppose the developers of Java only went one level deep so they don't have to consider checking types within types within types etc.
I suggest putting #SuppressWarnings("unchecked") either above that line of code, or above the function its in and not worrying about such limitations of Java compiler warnings ;) 
"Levels" don't have anything to do with this.
Simply put, the generics cannot check whether the cast is valid, so a warning is issued.
In a working generics situation, having a Map<String,String> means that at compile time you know that there are only Strings in the Map. Here you get a warning, because it's not certain that it is the case (i.e. you don't have compile time type safety) and Java just wants to make sure you know what you're doing.
And yes, like njbt7y said, a #SuppressWarnings("unchecked") will remove that warning if it bothers you. 
njbt7y and Kayaman,
Thank you both for your responses!
Kayaman:
You said "the generics cannot check whether the cast is valid, so a warning is issued". Could u tell me where you found this info, I'd like to read more upon it. Did u find it in the Java Language Specification?
Thanks! 
er**** wrote:
You said "the generics cannot check whether the cast is valid, so a warning is issued". Could u tell me where you found this infoWhen a method has Object as a return value and you cast it to a genericized class, the generics mechanism is helpless in determining whether that cast will fly or not. But I'm sure it's described more eloquently somewhere in the JLS. 
Thank you Kayaman for your insightful answer! I thought your answer was eloquent enough! ;) Your answer has been marked "Correct".
Edited by: er**** on 09-Jan-2011 13:14 
Just wrapping up the discussion:
I created the following code in Eclipse:
Object x3= new Person();
Person x4= (Person)x3;
It did not produce a warning. Therefore this statement doesn't appear to be quite correct:
"the generics cannot check whether the cast is valid, so a warning is issued"
Although it cannot check weather the cast is valid, it will not issue a warning. 
There are no generics in that code for the statement "the generics cannot check whether the cast is valid, so a warning is issued" to apply to. 
njbt7y wrote:
Person x4= (Person)x3;
Although it cannot check weather the cast is valid, it will not issue a warning.The compiler can't guarantee that the case is successful, but the runtime can check if it is.
So if x3 does not reference a Person object, then it will throw a ClassCastException.
However, looking at:
List<String> foo = (List<String>) bar;This will produce a warning, because even at runtime the JVM can't guarantee that bar actually references a List<String> (it can only check if it's a String). So it does an "unchecked conversion": it accepts the cast even 'though some of its details could not be verified.
At runtime, when bar references something that is not a List, then you will get a ClassCastException as usual. But if it is another List (for example a List<Integer>), then no exception will be thrown (technically, because at runtime there are no "List<Integer>" or "List<String>", but only "List" objects: that technique is call erasure). 
[url http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#Topic4]Additional info on Generics

Categories

Resources