DRAFT: Project Jigsaw: The Big Picture (part 1)
Julien Ponge
julien.ponge at gmail.com
Wed Dec 21 01:31:03 PST 2011
Mark,
I have a bunch of those except flames. So here they are, for what they're worth.
> Most applications do not need to add or remove modules dynamically at
> run time, nor do they need to use multiple versions of the same
> module simultaneously. The module system should be optimized for
> common scenarios but also support narrowly-scoped forms of dynamic
> multi-version resolution motivated by actual use cases such as, e.g.,
> application servers, IDEs, and test harnesses.
>
>
Granted, a significant share of applications simply rely on avoiding ClassNotFoundException. Nevertheless there is also a significant share of applications that require some form of side-by-side versioning, dynamic (un)loading and the ability to access functional units through a service locator of some form. This is basically any kind of application that needs to manage some form of lifecycle. This is not just containers: applications deployed to containers often have to deal with dynamic, e.g., a dependent module appearing or disappearing.
While I agree that optimizing for static modules matches a reality, you should not be scared of providing a sensible solution to the dynamic cases. Otherwise people will necessarily hack on top of your APIs and come up with incompatible and discussable solutions.
People have adopted systems like OSGi, or came up with solutions on their own involving classloader wizardry. They may not be perfect but at the very least they do work now.
Narrowly-scoped solutions may be advisable, but at the very least they must not reject prior art that was validated by real needs, especially if you put the long adoption cycles of Java releases into the balance.
> The module system does not support general dynamic run-time resolution;
> i.e., it is not possible to add or remove dependences or modules after an
> application has started running. Sophisticated container-type programs
> such as application servers, IDEs, and test harnesses can achieve the
> effect of run-time resolution in a limited way by using the module-system
> API to install modules into a temporary module library and then run them
> from that library.
>
> > TODO: Finish implementing run-time module-path support.
>
> > TODO: Design and implement container support.
No flame here, but again, this is where Jigsaw will either win or become yet another java.util.logging.
Implementing a container within the JDK would be a mistake, but this does not prevent from adding the support for adding/removing modules at runtime. Do you have any public document discussing the possible approaches for your APIs contracts?
I guess that you will be able to dynamically load a module like you can load a class from a classloader, but without the ability to unload then people will fall in the traps where others (OSGi?) fell: reliance of the GC to clean up, hoping that no stale references exists, etc.
> A module's `exports` declarations govern the [accessibility][acc] of the
> public types declared in the named packages. It is thus enforced at both
> compile time, by the Java compiler, and at run time, by the virtual
> machine.
>
>
Correct me if I'm wrong, but this is the same as OSGi export clauses, right?
I always felt like it was weird to have public classes that in reality are not being made visible at the package level. In OSGi this leads to JARs / bundles / modules that have public types not being really public depending on the runtime context (classpath, OSGi, etc).
Why not rely on the compilation unit visibility? Like introducing a "module protected visibility" without managing it at the module metadata level? I tend to think that "module protected class Foo { }" is cleaner than "public class Foo { }" only to be made "hidden" in module-info.java by not having a corresponding exports clause.
> The `public` modifier makes the types imported into `bar` from `foo`
> available to any other module that depends directly upon `bar`.
>
It may be just me, but I don't find it explicit to have "requires public foo" meaning that the module re-exports from foo. 'reexports foo" as a separate clause may be more readable, although slightly less concise.
But isn't the seminal "The Feel of Java" article all about explicit/readable over implicit/concise? :-)
> In this case any other module that depends upon either `bar` or `baz`
> will be able to use public types exported by `foo` without depending upon
> `foo` itself
Can't this lead to unexpected types visibility at runtime depending on which module was actually resolved as a dependency? Wouldn't it be useful to be defensive regarding what imports bring you in crappy modules by having the possibility of filtering?
Or maybe the "permits" clause could be used just for that?
> > ISSUE: Should aliases have version numbers? The syntax currently
> allows them. They appear to be necessary to support refactoring by
> aggregation. In popular native packaging systems, however, the natural
> mapping of a module alias is to a virtual package, and virtual packages
> don't have version numbers.
I think that they should have version numbers, e.g. "java-base @ 1.8" vs "java-base @ >= 1.9", otherwise aliases will be a second-class citizen kind of naming scheme.
> > ISSUE: Should each module in a set of modules related by local
> dependence be required explicitly to permit all the other modules?
> That is not the case today, but it is arguably safer.
>
>
I think so.
> A non-default view can, finally, also declare an entry point different
> from that of its containing module's default view, so a single module can
> define multiple related entry points. For example, the declaration
>
> module commands {
> view cat {
> class org.foo.commands.Cat;
> }
> view find {
> class org.foo.commands.Find;
> }
> view ls {
> class org.foo.commands.List;
> }
> }
>
> defines three entry points: `cat`, `find`, and `ls`.
You may want to add a sentence and/or example to say how "java -m Foo" can pick one view or the other.
> Services
What you have here sounds good in principle, especially using ServiceLoader, but we again get to the point of dynamics.
On one hand you have a nominal static module system and a mechanism to bind to services provided by modules in a decoupled fashion. Great. On the other hand you seem not to be willing to have full dynamic modules + services + lifecycle notifications although you seem to intend that there will be an API to still load them dynamically… which means that Jigsaw may likely end up being half-baked here… meaning that people will hack on top of that or resort to solutions like OSGi which will most likely not be 100% 2-ways compatible and have their own issues.
Today is the chance to provide a clean language + JVM solution to address dynamics instead of letting people come up with hacks. Balkanization is what the Java community would rather avoid I suppose.
I'm sure an open discussion such as the ones you are initiating on this list can only lead to pragmatic consensus… and eventually a much needed JSR once it stabilizes.
Cheers
--
Julien Ponge
http://julien.ponge.info/
On Wednesday, December 21, 2011 at 12:28 AM, mark.reinhold at oracle.com wrote:
> I've started drafting an overview of the current state of Jigsaw.
> The first part is attached below, and also available on the web:
>
> http://cr.openjdk.java.net/~mr/jigsaw/notes/jigsaw-big-picture-01
>
> Comments, questions, and suggestions welcome. Flames will be ignored.
>
> - Mark
>
>
> Attachments:
> - jigsaw-big-picture-01.md
>
More information about the jigsaw-dev
mailing list