A way to opt out of access restrictions on non-exported members.

Peter Levart peter.levart at gmail.com
Wed Nov 18 08:03:32 UTC 2015



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



More information about the jigsaw-dev mailing list