I'm having some trouble with my inheritance structure for a bunch of wrapper classes with generics. This is basically the structure:
public abstract class SuperWrapper<E extends Super>{
private E wrappedObject;
public E getWrappedObject(){
return wrappedObject;
}
}
public abstract class MiddleWrapper<E extends Middle> extends SuperWrapper<E>{}
public class SubAWrapper extends MiddleWrapper<SubA>{}
public class SubBWrapper extends MiddleWrapper<SubB>{}
The classes that are wrapped follow the same inheritance structure, so basically:
public class Super{}
public class Middle extends Super{}
public class SubA extends Middle{}
public class SubB extends Middle{}
These wrapped classes are not mine and can not be changed (which is the reason for the wrapper classes). This structure works very well for most purposes, however there are some problems when I want a method to return either a SubAWrapper or a SubBWrapper.
This is what I've tried so far:
public static MiddleWrapper<?> findMiddle(String id){
SubAWrapper a = new SubAWrapper();
SubBWrapper b = new SubBWrapper();
if(returnSubA){
return a;
} else{
return b;
}
}
This compiles and works but SonarQube warns about the use of a wildcard in a return type and from my googling it's not one of the warnings that should be ignored.
Another way:
public static <E extends Middle> MiddleWrapper<E> findMiddle(String id){
SubAWrapper a = new SubAWrapper();
SubBWrapper b = new SubBWrapper ();
if(returnSubA){
return (MiddleWrapper<E>) a;
} else{
return (MiddleWrapper<E>) b;
}
}
This compiles and works with the current code, BUT, it seems dangerous. If the caller uses this method like this: MiddleWrapper<SubA> middle = findMiddle("1");
it will compile fine but if findMiddle tries to return a SubBWrapper there will be a ClassCastException at runtime. What I though would work but didn't was:
public static MiddleWrapper<Middle> findMiddle(String id){
SubAWrapper a = new SubAWrapper ();
SubBWrapper b = new SubBWrapper ();
if(returnSubA){
return (MiddleWrapper<Middle>) a; //Compile error here
} else{
return (MiddleWrapper<Middle>) b; //and here
}
}
So my question is basically, is there a correct way to write the method findMiddle that compiles, runs and follows best practices?
For extra credit, is there a way to write a method so that it returns a list containing both SubA and SubB. Like this but without the wildcard:
public static List<MiddleWrapper<?>> getAllMiddle(){
List<MiddleWrapper<?>> ret = Lists.newArrayList();
ret.add(new SubAWrapper());
ret.add(new SubBWrapper());
return ret;
}
ps. At this point we're still using Java 6 but an upgrade to Java 8 is scheduled for next year so solutions using Java 7-8 functionality will still be useful eventually.