On 11/16/2015 07:57 PM, Alan Bateman wrote:
On 16/11/2015 17:48, Neil Bartlett wrote:
Alan,

In your consideration does the following declaration break encapsulation of a module, assuming that package “org.example.impl” is not exported?

    module foo {
provides org.example.api.ServiceInterface with org.example.impl.ServiceImpl;
    }

This appears to allow the ServiceLoader to punch through encapsulation and obtain instances of a non-exported type.
Sure, but this just part of the support for services. In this example then the service provider is fully encapsulated. The consumer of the service can't access ServiceImpl, it instead accesses it via ServiceInterface (assuming of course that the consumer reads the module with ServiceInterface and org.example.api is exported to the consumer).

How does this differ from a declaration that one might see in a Dependency Injection framework such as Spring? I.e. something like:

    <bean class=“org.example.impl.ServiceImpl”> …

There isn't way to give Spring super powers so this needs foo to export org.example.impl to Spring.

-Alan.

Hi,

Just a thought (and I don't know yet if it is a good idea)...

ServiceLoader currently has the following method:

public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)

With the following overload:

public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader, Function<Stream<Class<?>>, Stream<Class<?>>> streamManipulator)

We (or Spring) could use it like:

    ServiceLoader<ServiceInterface> loader = ServiceLoader.load(
        ServiceInterface.class,
        classLoader,
stream -> stream.filter(implClass -> implClass.getName().equals("org.example.impl.ServiceImpl"))
    );

This could also be used to code various other strategies for service lookup, for example:

    public @interface Order {
        int value() default 100;
    }

    ServiceLoader<ServiceInterface> loader = ServiceLoader.load(
        ServiceInterface.class,
        classLoader,
        stream -> stream.sorted(
comparing(implClass -> implClass.getAnnotation(Order.class), comparing(Order::value))
        )
    );


This way the powers of instantiating the implementation classes are left to ServiceLoader, but client can decide what implementation classes are chosen.


Regards, Peter

Reply via email to