This is an educational question that relates to a hobby project. Project Spring Boot MVC/REST app.
I would like to retain the flexibility to be able to create multiple implementations of Service and have list return a list of objects, depending on what the implementation requires.
I appreciate I could create some inheritance/implementation hierarchy to define the kinds of objects of which T could encompass. My problem with both of those answers is that some use cases for Service involve me needing to return Lists of Java Standard Lib types - types I would rather not inherit/extend/implement for my own custom classes, which I would prefer be kept as lean as possible.
import java.util.List;
interface Service {
<T> List<T> list(String location, MyEnums.mediaType type );
}
class MyEnums {
enum mediaType {
IMAGE, VIDEO, AUDIO
}
}
class LocalService implements Service {
public List<MyConcreteClass> list(String location, MyEnums.mediaType type ) {
List<MyConcreteClass> list = null;
list.add(new MyConcreteClass(1, "foo", new byte[0]));
return list;
}
}
class MyConcreteClass implements Comparable<MyConcreteClass> {
private final long id;
private final String name;
private final byte[] data;
public MyConcreteClass(long id, String name, byte[] data) {
this.id = id;
this.name = name;
this.data = data;
}
@Override
public int compareTo(MyConcreteClass o) {
return this.name.compareTo(o.name);
}
// Other methods omitted for brevity
}
The above code is only a simplified example of the actual app code - which compiles and runs without any (known) runtime bugs. However I get the compiler warning:
Unchecked overriding: return type requires unchecked conversion.
The presence of a warning makes sense to me - code consuming the Service interface/API could break at runtime if the return type requirement in the calling code is incompatible with the implementation, whereas the error would be caught at compile if I had a more specific List<> defined in the interface.
This would, of course, not be an issue if I had to wire in a concrete implementation into the code consuming my service - however the joys of Spring!
What am I doing wrong? How can I fix this? Are generics the right way to achieve a polymorphic list() function in my case?
CodePudding user response:
You can eliminate the unchecked cast by declaring the interface itself with a type parameter (instead of the method). Like this:
interface Service<T> {
List<T> list(String location, String type );
}
class LocalService implements Service<MyConcreteClass> {
@Override
public List<MyConcreteClass> list(String location, String type ) {
// Some logic to retrieve, alter and return a list
return null;
}
}
class StringService implements Service<String> {
@Override
public List<String> list(String location, String type) {
// TODO Auto-generated method stub
return null;
}
}
class MyConcreteClass {
/// ...
}
(I changed a couple of things to make it compile, not relevant to the answer).