Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can it be that Java is NOT type safe in a particular situation?

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, ...?

like image 815
brainsheep Avatar asked Jan 16 '13 16:01

brainsheep


People also ask

Why is Java not type-safe?

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.

How do you ensure type safety in Java?

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.

Why is Java called type-safe language?

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.

Is Java script type-safe?

Javascript (alongside Java, Ruby, Haskell) is a type safe language (whereas C is not).


1 Answers

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.

like image 60
Jon Skeet Avatar answered Oct 26 '22 13:10

Jon Skeet