Search code examples
javagenericsapi-design

API design question, generic method with generic class


A musical score contains Item objects. All Items have a Position and associated data. Data can be anything, a note, lyrics, etc.

interface Item<T>
{
     Position getPosition();
     T getData();
     ...
}

class NoteItem implements Item<Note>
{        
    Note getData() { .... }
    ...
}

class LyricsItem implements Item<Lyrics>
{
    Lyrics getData { ... }
    ...
}

The Score class has a method to get Items of a specific class:

public <T extends Item<E>, E> List<T> getItems(Class<T> itemClass)
{
  //
}

As shown below, getItems() works if parameter is a subclass of Item. But if it's Item.class, return value is a list of objects, I expected a list of Items...

NoteItem item = getItems(NoteItem.class).get(0);  // Compiles OK
Item<?> item2= getItems(Item.class).get(0); // Compiles KO, return value is Object, not Item<Object> as I expected

I can fix the 2nd line by explicitly casting the result to (Item<?>), but is there a better way to avoid the casting ?

One solution to avoid the casting is to change the getItems() method to:

 <T> List<T> getItems(Class<T> aClass)

but then the user of the method has no way (besides doc) to know that the method only accepts Item classes. What would be the best way to handle this ?


Solution

  • Not sure it's the best solution but I ended up using the following getItems() method:

     <T extends Item<?>> T getItems(Class<T> itemClass);
    

    which makes the 2 lines work:

    NoteItem item = getItems(NoteItem.class).get(0);  // Compiles OK
    Item<?> item2= getItems(Item.class).get(0); // Compiles OK
    

    The only minor drawback is that I get a rawtypes warning when I use getItems(Item.class) because return value is List<Item>, not List<Item<?>>.