Missing a wildcard open statement
Kasper Nielsen
kasperni at gmail.com
Wed Jan 16 16:06:49 UTC 2019
On Tue, 15 Jan 2019 at 07:48, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> Which library or framework is this and is there a write-up of the issues
> encountered when migrating it to use Lookup objects?
>
> -Alan
>
It is a small dependency injection/application I am trying to built on top
of the module system.
It is not in finished form yet, however, I have made some notes about some
observations I've done.
# Naming / User Friendliness
I know this is to late to change, but I think the Lookup mechanism could
have been designed a bit more user friendly.
Here is a simple method that lets a user construct a new object using
dependency injection. The two parameters are: The type of object that
should be constructed, and a Lookup object that can be used by the
underlying framework for invoking a constructor on the specified type.
import java.lang.invoke.MethodHandles;
public <T> inject(Class<T> type, MethodHandles.Lookup lookup)
Having Lookup defined as a static nested class of MethodHandles kind of
requires you to introduce two topics at the same time. It is quite a bit to
explain if you only have 10 lines for a getting started guide. Especially
since the usage of both of them are more or less unknown to 99% of Java
developers.
I could use this signature
import java.lang.invoke.MethodHandles.Lookup;
public <T> inject(Class<T> type, Lookup lookup)
But unless you know how to acquire a lookup object, it is a bit hard to
figure out you need to look in its parent object to find the method.
Buried, among tons of other methods. I think adding a static method such as
Lookup.of() could make it a bit less painful. Its still a bit difficult to
explain why this is needed without getting to technical. But I hope this
will change if it sees widespread use.
# Single Module
In general, Lookup objects are really easy to work with when you are have a
_single_ module that has a dependency on a library that needs a Lookup
object to be initialized. And you are in full control of initializing the
library.
# Inversion of Control/Container deployment
Here I am thinking about something like how people would normally deploy a
modern servlet WAR; A bunch of annotated classes packaged in a single jar.
Since your code is being initialized by the container you cannot directly
handoff a Lookup object to the container. Instead you need to rely on some
kind of delivery mechanism. For example, by requiring all deployable
bundles to provide a service (that secretly exposes the Lookup object) via
a ServiceLoader to the container. However, this quickly gets complicated
because if you work with something like Jakarte EE, where you have to
provide a standardized mechanism. With which any implementor can get a hold
of the provided lookup object. But at the same time make sure no one else
can read it.
This is an issue with qualified open statements via module-info as well. If
you do not know which implementation you are going to deploy your WAR in.
You cannot use a qualified open statement. So you are left with "open
module", which I suspect will be how things are going to work for a long
time.
Some of these issues might be solvable by using something like Module
layers.
# Multiple Modules
If your application consists of multiple modules. For example, you might
have some customer-services in one module and some order-service in a
another module. Then a third module that kind of glues the two modules
together. You might also have a DI framework, a JPA implementation and a
JaxRS container.
It is a bit of similar problem here, you need to handoff a Lookup object
from customer-services->main module and from order-services->main module.
And then the main module then needs to initialize each library with each of
the Lookup objects for every module.
You also sometimes get into some complex situations where an abstract class
is located in one module, and the concrete class in another module. Each of
them having an annotated method/field that you need to access. So you need
one Lookup object to access the method on the abstract class and another
Lookup object to access the method on the concrete class. Depending on how
you track your Loookup objects, you worst case end of with API's like this
public <T> inject(Class<T> type, MethodHandles.Lookup... lookup) and then
some complex logic to match methods with Lookup objects.
I actually really like working with Lookup objects. However, I think it
potentially could end up with a lot of micro management for larger projects.
And then people are going to be, fine, lets just put open module everywhere.
/Kasper
More information about the jigsaw-dev
mailing list