tags:

views:

156

answers:

3

I have the following classes:

abstract class DTO{ }

class SubscriptionDTO extends DTO { }

and the following generic method:

protected void fillList(ResultSet rs, ArrayList<? extends DTO> l)
  throws BusinessLayerException {
 SubscriptionDTO bs;
 try {
  while (rs.next()){
   //initialize bs object...
   l.add(bs); //compiler error here
  }
 } catch (SQLException e) {
  e.printStackTrace();
 }

}

I can't seem to understand why you can't create a generic method for filling DTO subtypes. Am I doing something wrong or is this by design? If so, is there any workaround? Thanks in advance.

+7  A: 

You should be using <? super DTO> (or <? super SubscriptionDTO>, as Tom Hawtin - tackline points out) as the generic parameter of the ArrayList.

From item 28 of Effective Java (page 28 of the sample chapter [pdf]):

Here is a mnemonic to help you remember which wildcard type to use:

PECS stands for producer-extends, consumer-super.

In other words, if a parameterized type represents a T producer, use <? extends T>; if it represents a T consumer, use <? super T>.

In this case, l is a consumer (you are passing objects to it), so the <? super T> type is appropriate.

Michael Myers
Or <? super SubscriptionDTO>.
Tom Hawtin - tackline
+1  A: 

Imagine the following situation, with Foo extends Bar and Zoo extends Bar

List<Foo> fooList = new ArrayList<Foo>();
fooList.addAll(aBunchOfFoos());
aMethodForBarLists(fooList);

then we have the method itself:

void aMethodForBarLists (List<? extends Bar> barList) {
   barList.add(new Zoo());
}

What happens here, is that, even though Zoo does extend Bar, you're trying to add a Zoo in a List<Foo>, which is explicitly made for, and only for, Foos.

This is why the Java spec disallows adding stuff into a <? extends Something> Collection - it can't be sure that, while the syntax seems right, the actual objects would allow adding stuff into the Collection.

Henrik Paul
+2  A: 

This should work, and is more straightforward:

protected void fillList( ResultSet rs, List<DTO> l ) throws BusinessLayerException 
{
   SubscriptionDTO bs;
   try 
   {
      while   ( rs.next() )
      {
         //initialize bs object...
         l.add( bs );
      }
    }
    catch ( SQLException e ) 
    {
       e.printStackTrace();
    }

}

alasdairg