Search code examples
javagenericsfactory-pattern

Generic factory of generic containers


I have a generic abstract class Factory<T> with a method createBoxedInstance() which returns instances of T created by implementations of createInstance() wrapped in the generic container Box<T>.

abstract class Factory<T> {
    abstract T createInstance();

    public final Box<T> createBoxedInstance() {
        return new Box<T>(createInstance());
    }

    public final class Box<T> {
        public final T content;

        public Box(T content) {
            this.content = content;
        }
    }
}

At some points I need a container of type Box<S> where S is an ancestor of T. Is it possible to make createBoxedInstance() itself generic so that it will return instances of Box<S> where S is chosen by the caller? Sadly, defining the function as follows does not work as a type parameter cannot be declared using the super keyword, only used.

public final <S super T> Box<S> createBoxedInstance() {
    return new Box<S>(createInstance());
}

The only alternative I see, is to make all places that need an instance of Box<S> accept Box<? extends S> which makes the container's content member assignable to S.

Is there some way around this without re-boxing the instances of T into containers of type Box<S>? (I know I could just cast the Box<T> to a Box<S> but I would feel very, very guilty.)


Solution

  • Try rewriting your other code to not use Box<S> but instead uses Box<? extends S>, so it will accept a Box<T>, too. This way, you make it explicit that the Box may also contain subclasses of S.

    The following should also work, if you make your Box static:

    public static <S, T extends S> Box<S> createBoxedInstance(Factory<T> factory) {
      return new Box<S>(factory.createInstance());
    }
    

    However, it may be unable to do type inference for S, at which point you need:

    public static <S, T extends S> Box<S> createBoxedInstance(Factory<T> factory, S dummy) {
      return new Box<S>(factory.createInstance());
    }
    

    Another variation that is very explict:

    public static <S, T extends S> Box<? extends S> createBoxedInstance(Test<T> factory, S dummy) {
      return factory.createBoxedInstance(); // Actually a Box<T>
    }