Search code examples
javagenericsserviceloader

ServiceLoader where type parm is itself generic


class ServiceLoader<S> implements Iterable<S> {
    // ...
}

interface Foo<T> {
    // ...
}

class FooRepository {
    void add(Iterable<Foo<?>> foos) {
        // ...
    }
}

FooRepository repo = new FooRepository();
repo.add(ServiceLoader.load(Foo.class));

This yields a compiler error: "The method add(Iterable<Foo<?>>) in the type FooRepository is not applicable for the arguments (ServiceLoader<Foo>)".

I was hoping to be able to treat an Iterable<Foo> as an Iterable<Foo<?>>, but on its own it doesn't seem to work. What would be the cleanest way to transmute the result of ServiceLoader.load(Foo.class) into something I can feed to FooRepository.add()?


Solution

  • If you're talking about java.util.ServiceLoader<S>, then its Javadoc says:

    The provider class is typically not the entire provider itself but rather a proxy which contains enough information to decide whether the provider is able to satisfy a particular request together with code that can create the actual provider on demand. [...] The only requirement enforced by this facility is that provider classes must have a zero-argument constructor so that they can be instantiated during loading.

    Combined with the way that the provider class is clearly instantiated using reflection, that tells me that a provider class declared with a generic type argument will in fact be instantiated as a raw type.

    Thus, because you're passing in an object of type Class<Foo> -- and there's no way in Java to construct a object of type Class<Foo<Bar>> -- then what you get back is what you asked for, an Iterable<Foo>, where Foo is the raw type created from Foo<T>.

    Unfortunately, I think the simple answer is: Don't do that then! Either make your provider class be a concrete subclass of the generic type, or else make your provider class be simply a factory that can construct new objects of the appropriate generic type.

    Honestly, I can't think of any good reason to make a generic service provider class anyway -- where would you provide the type arguments? I think the factory mechanism is your best bet.