2

I maintain 2 projects with the same functionality and I am consolidating this functionality into a commons project. I defined an interface:

public interface GraphData 
{
    public List<? extends ShapeData> getShapes();
    public void setShapes( List<? extends ShapeData> shapes );
}

I implement this interface in both projects:

public class Graph implements GraphData 
{
     public List<Shape> shapes = new ArrayList<Shape>();

     public List<? extends ShapeData> getShapes() 
     { 
         return shapes;
     }

     public void setShapes( List<? extends ShapeData> shapes )
     {
        this.shapes = shapes;
     }
}

Shape is a subtype of ShapeData. When I compile this class I get an error about casting List<Shape> to List<? of... How do I resolve this compilation error? Maybe a better question is, should I define my interface methods using the bounded wildcard (i.e. ? extends)?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
user1277290
  • 21
  • 1
  • 2

2 Answers2

9

Basically, your interface is too broad IMO. You've specified that shapes (which is a public field, by the way - why?) must be a List<Shape>. What would you expect to happen if someone passed in the wrong kind of list to setShapes? For example:

public class BadShapeData implements ShapeData { ... }

...

List<BadShapeData> badShapes = new ArrayList<BadShapeData>();
new Graph().setShapes(badShapes);

That's not a list of Shape, is it?

You can fix it by making your interface generic:

public interface GraphData<T extends ShapeData>
{
    List<T> getShapes();
    void setShapes(List<T> shapes);
}

Then:

public class Graph implements GraphData<Shape>

Alternatively, you could change your interface not to have the setter. Do you really need it? Is the interface really adding much benefit? Can you not provide more meaningful operations on it than just a property?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

I think it's complication for its own sake. Your Graph has a List<Shape>; get and set that type as well.

public interface GraphData 
{
    public List<Shape> getShapes();
    public void setShapes(List<Shape> shapes );
}

I usually don't have getters/setters in interfaces. That's not very meaningful or interesting behavior. I don't agree that an interface is even necessary for Graph. You might want to think about what you're trying to achieve.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • Let me expand on my initial post. The GraphData and ShapeData interfaces are located in my commons project. The 2 projects that depend on my new commons project have Shape classes that are subtypes of ShapeData. getShapes is common to both Shape classes however there is functionality in each Shape class that is specific to a project. Thus, the Shape object does not exist in my commons project and I can not define simple getters and setters (i.e. List getShapes() and setShapes(List shapes). – user1277290 Mar 18 '12 at 21:55