views:

59

answers:

5

I'm refatoring a home-grown DAO container, hoping to make the class generic. It internally uses an ArrayList to store the retrieved objects.

One usage of this class puts the container's list into a request scope, and due to a limitation of Websphere, I can't pass the generic List<Foo> to the request scope (Websphere doesn't handle generics out-of-the-box)

If I go ahead with my refactorings, I will need to convert/cast the List<Foo> into a non-generic List object..

// Boils down to this...
List<Foo> listFoo = new FooListing().findAllFoo();
List listThings = listFoo;
request.setAttribute("listThings", listThings);

What are the implications of reversing a generification like this? Should I avoid doing this kind of manipulation?

EDIT: The code snippet is verbose to explicitly demonstrate what I'm describing..

+3  A: 

If the component type of the List does match the expected type, there is no problem.

Generics in Java are only used for type-checks by the compiler, they have not effect at runtime. If you are using an older library that does not support generics, you have no choice but to ignore the generic type. Things should continue to work, as this system has been designed with backwards compatibility in mind.

So all you are losing is the compile-time type checking (it puts you back to where Java was at 1.4, which means, if the types match, everything will work, if not, you'll get ClassCastExceptions or other unwanted behaviour at runtime).

However, I think you can just write

request.setAttribute("listThings", listFoo);

This method takes any kind of Object. Even if it wanted a List, you could still pass a List<Foo> (which is still a List).

Thilo
Cool, just wanted to explicitly demonstrate what I was describing in the code example
brass-kazoo
You can pass your `List<Foo>` to every method that wants a non-generic List. WebSphere cannot interfere with that. This is how the backwards-compatibility works.
Thilo
A: 

First, you can't cast a generic to a non-generic list so yeah you'd have to convert it.

Second, the two main advantages to a generic list are 1) it ensures that all objects are of the specified type and 2) it allows you to directly access methods of the object collection without needing to recast them. This allows you to write cleaner code and saves some processing cycles from having to cast back and fourth.

Neither one of these advantages is a dire need however. If you can't use them you won't notice a difference in performance. Your code may look a little messier though.

Spencer Ruport
You absolutely can cast a generic to a non-generic list. You may have to suppress the warning, but you absolutely can do it. Which makes sense since they're exactly the same type after erasure.
polygenelubricants
"you can't cast a generic to a non-generic list". You can write `List x = (List) listFoo`.
Thilo
Ah my bad. I must have been thinking "you can't cast one generic list to another generic list" and gotten it mixed up in my head.
Spencer Ruport
+2  A: 

Java uses "type erasure" for generics -- essentially that means that the compiler checks the generics, but the runtime forgets all about it and just treats it as a list of objects.*

Whenever you treat a List<Foo> as just a List, you won't get compiler checks to make sure you don't put a Bla into your list. So you could get a ClassCastException if you call List<Foo>.get() and it turns out to be a Bla hiding in the list. But that can only happen if you some code puts a Bla in your list.

If you wan't to be cautious, then if you pass the List<Foo> as a List to anything that might add a non-Foo to the list, don't treat it as a List<Foo> whenever you access it, but treat it as a list of Objects and add instanceof checks.

*Some of the information is accessible at runtime, but let's not complicate matters.

William Billingsley
Luckily, the usage of the list in this case is only for display purposes, so there's no risk of bla exploding in our faces
brass-kazoo
A: 

I have similar problems with Weblogic Portal. Just use none-generic type for this case.

Artic
+1  A: 

A "non-generic" version of a generic type is called a "raw type".

Passing a generic type where the raw equivalent is requested is generally ok. This is actually the main reason generics in Java work the way they do (with erasure): to enable interoperability between "generified" code and pre-generics code.

The main thing you need to be careful about is that if you pass a List<Foo> to something that askes for a List, they may put non-Foo objects into the List. You won't get any compile time checking to help you here. You do get some runtime checks: a ClassCastException will be thrown when you use a method that returns a Foo on your List<Foo> and it has to return a non-Foo.

If you want more fail-fast behavior you can wrap your List<Foo> with Collections.checkedList() to get a List that'll check the type of elements on insertion.

Things get more complicated if Foo itself is a generic type. Runtime checks are only done on reified types (ie: the type with generic type parameters removed) so if you give them a List<Set<Bar>> and they insert a Set<Baz> or just a Set, you won't know since the runtime/reified type of the element is Set either way.

Laurence Gonsalves