Today I found a very very weird behavior of the JVM, a (normally type-safe) List<Date>
did actually hold a List<MyObject>
at runtime!
I wonder how that ever could happen, but couldn't find anything in the web.
That's the situation:
I'm working with Spring Data JPA 1.2.0
on a JBoss EAP 6.0 Server
with JRE 1.6.0_18-b07
.
By mistake, in a Spring Data JPA Repository
class there was written a wrong result type in the @Query
expression. It should have been:
@Query("select distinct trunc(record.orderDateTime) from MyType record [...]" )
public List<Date> getOrderDates(...);
But was:
@Query("select record from MyType record [...]" )
public List<Date> getOrderDates(...);
So, the aim was to load a list of dates (java.util.Date
), which works fine if the query is properly defined as in the first code snippet.
But that coding mistake led to the following result:
At runtime, there actually WAS a List<MyType>
returned, even though the method's signature defines a List<Date>
. Also in my model an attribute of List<Date>
was/contained a List<MyType>
. I debugged it and couldn't believe my eyes!
I could even write the content of this list to a JSP (I only recognized this weird behavior because a JSP couldn't be displayed any more due to a Spring Expression Language error occuring with the attempt to type match from MyType
to Date
, which of course had to crash).
Hell, shall I now loose my believe in the type-safety of Java?
Has anybody ever had such a problem?
Does an explanation for this exist?
And can I do anything to fix that or is it a general issue? Maybe another version of the JRE, JBOSS, ...?
Java is not type-safe because it allows a very powerful way of organizing the type-space at run-time (through user-extensible class loaders ). This power can be utilized to write a program that exposes some flawed design decisions in the Java Virtual Machine.
Java labels every object by putting a class tag next to the object. One simple way to enforce type safety is to check the class tag of the object before every operation on the object. This will help make sure the object's class allows the operation. This approach is called dynamic type checking.
Type Safety C# is primarily a type-safe language, meaning that types can interact only through protocols they define, thereby ensuring each type's internal consistency. For instance, C# prevents you from interacting with a string type as though it were an integer type.
Javascript (alongside Java, Ruby, Haskell) is a type safe language (whereas C is not).
I wonder how that ever could happen, but couldn't find anything in the web.
It happens because generics are mostly a compile-time-only feature. Metadata is maintained in terms of a class's type parameters, fields etc... but at execution time, type arguments are (mostly) lost. For example:
Object x = new ArrayList<String>();
Object y = new ArrayList<Integer>();
System.out.println(x.getClass() == y.getClass()); // True
The JVM can't tell the difference - which is why you'll get a warning when you try to cast:
// At execution time, this cast will *really* only check for List
List<String> dodgyCast = (List<String>) y;
For the most part, the compiler keeps "regular" code using generics safe. But when you have things like ORMs providing values via reflection or dynamic byte code, all of that safety goes out of the window.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With