Optional Module Dependency
Mandy Chung
mandy.chung at oracle.com
Wed Jun 8 14:37:19 PDT 2011
Hi Roger,
On 05/20/11 13:54, Roger Riggs wrote:
> The terminology of "optional method" might be improved.
> The method itself is not optional; but its behavior is based on the
> presence
> of classes within a module that may not be present. The behavior depends
> on code to check the (class, module or configuration) dependencies and
> (in many cases) throw an exception. The @RequireModule annotation only
> seems to be informative.
Right.
@RequireModule annotation is for developer tools such as javadoc to list
all optional methods or highlight them in the javadoc if appropriate.
The runtime behavior depends on the implementation to check if such
dependency can be satisfied.
>
> The Module.isModulePresent(String mn) method might be renamed to
> isModuleAvailable
> since it includes the check for availability from the calling module.
>
I see both the term "present" and "available" don't precisely indicate it's
relative to the calling module. In that case, isModulePresent seems
preferable.
> Does the module name being checked include the version ? I.e.
> "jdk.jaxp at 1.4"
> Some dependencies will be relative to specific versions of the modules.
>
I don't see it needs to include the version. If the optional dependency is
specific to a particular version, isModulePresent("jdk.jaxp") returns true.
You can use Module.getVersion() to check the version or Class.forName
to check if a new API exists or not - see below for the Class.forName cost.
> There is a potential disconnect between testing for a module name and the
> specific dependency on a class.
> Developers may not be clear on the relationship between the Class names
> that are used in the code and the module packaging.
In the modular world, for committed and supported APIs, module and class
names relationship should be clear. For uncommitted and non-supported
APIs,
the vendor can move or remove them in incompatible way. Seems like
your concern is for the latter case in which it should use Class.forName
in my opinion. If an API is moved from one module "A" to another "B" and
not reexported to A, the module that depends on such API would have to be
updated to require B rather than A; otherwise, it can't find that class.
> As an example, in
> the webrev of java.util.Properties, the code that has the dependency is
> not in the same class as the test for the module. There may be a
> mismatch
> between the module name and the understanding of its contents.
The platform classes / modules are a special case. We would investigate
this
when we support aliases. The platform modules are strongly connected (i.e.
requires local) and currently loaded by the BootLoader for 2 reasons;
1. compatibility - all system classes are loaded by the null bootstrap
class loader
2. split package requirement
java.util.Properties is in the jdk.boot module and in the context with
jdk.boot+sun.jaxp
(+ other platform modules). jdk.boot module shouldn't depend on any
modules and it couldn't find jdk.jaxp. I think we should treat the
jdk.boot module
a special case that it should also find the contexts from jdk.base.
Is there other use case you think of?
>
> In many cases, Class.forName is the right function because it is
> specific.
> But for classes that are not present and not going to be present, it
> is too slow to be repeated often and the method be fail fast since the
> contents of the module are/can be known.
Class.forName in the modular world doesn't do the linear search on
the class path (no more classpath!!). The module class loader will
be able to do such check in a couple of lookups (once we implement
the fast configuration).
> Alternatively, would it be possible to have a (ClassLoader) method to
> test if
> a class was available but without the side effect of loading it?
>
I assume you want the class to be loaded if present. So Class.forName
can continue to be used.
> The embedding of module names in the source code may too rigid and
> lead to maintenance issues since changing the dependency will require
> changing the code and generating an updated module with a new version
> number.
> This may be less of problem if the module namespace is very carefully
> managed and is generic enough to allow substitution of equivalent
> implementation modules.
> It depends on how much flexibility can be accomodated in module name
> and contents.
> Could the argument to isModulePresent be an indirect reference through
> the module-info contents? That might help decouple the source code
> from the
> module relationships.
>
How?
> With respect the @RequireModule annotation on methods, I don't see that
> it provides much value. It documents the method as having a dependency
> but it will be hard to go beyond that. The method may or may not
> directly
> refer to the classes in the module. Without analyzing the control flow
> of the code it would be difficult for a tool to help the developer
> identify
> the dependencies that could not be met (at runtime) if the module was
> not present.
> (All modules have to be present at compile time.)
The value I see is for example when an application calls
Properties.loadFromXML,
an IDE can catch this and ask if the application should require jdk.jaxp
and add it
to its dependency so that this optional dependency can guarantee to be
satisfied at runtime.
The developer of the optional methods will be responsible to make sure
a ModuleNotPresentException is thrown if the requiring module is not
present.
>
> When refering to types that are not (going to be) present, care must
> be taken
> to ensure the classfile can be verified without needing to evalate the
> missing
> types. This can be a bit subtle. In my experience, the coding patterns
> that are easy to understand limit where references to optional types
> may be
> used.
Good point. I'm checking with Alex Buckley further on the verification
side.
We probably have to come up an idiom that prevents a class referencing
the optional types being verified unless the optional module is present.
> If there is an annotation, it might be most useful if it is placed in the
> source at a point that reinforces the way verification works but I
> haven't
> thought this through. (For now, annotations can only appear in some
> places.)
>
Thanks for the comments. I'll send out an updated webrev some time.
Mandy
> Thanks for the chance to comment,
> Roger
>
>
>> I have implemented the new @RequireAnnotation annotation and a new
>> API (Module.isModulePresent method) to test whether a module has been
>> resolved and linked.
>>
>> This note summarizes for the optional module dependency work:
>> http://openjdk.java.net/projects/jigsaw/doc/topics/optional.html
>>
>> Webrev:
>>
>> http://cr.openjdk.java.net/~mchung/jigsaw/webrevs/require-module-annotation/
>>
>> A few questions to discuss:
>> 1. There are some APIs that require another module depending on the
>> input parameters passed in. Bidi, JNDI, JMX are some examples. The
>> optional module is guaranteed to be present when the given input
>> parameter depends on it.
> The requirement is on the type of the input parameters (not the values).
>>
>> I wonder what the best practice or recommendation of using
>> @RequireAnnotation. For APIs that throws ModuleNotPresentException,
>> they clearly need to be annotated so that javadoc and other tools can
>> process them when appropriate.
>>
>> I think it's generally a good idea to annotate the source of an
>> optional dependency so that a tool can check if the optional
>> dependency is declared in the module-info.java (if there is no static
>> reference to types from the optional module; otherwise, the compiler
>> can detect that). If a module P didn't declare the optional
>> dependency on M and M is present, P will be compiled successfully.
>> At runtime, isModulePresent method will return false even if M is
>> present but it is not visible to P. P's module class loader will
>> fail to find a class in module M. This is the case the new test
>> "optional-method.sh" shows.
>>
>> I currently put this annotation in these APIs (e.g.
>> sun.text.bidi.BidiBase, com.sun.jmx.mbeanserver.Introspector, etc).
>> Alan mentioned in an offline discussion I had with him if it's more
>> appropriate to have a different annotation for this type of
>> dependency. Any other thought?
> Figure out the semantics of the annotation and then revisit the name.
>>
>> 2. Class.forName is the existing (legacy) approach to determine if a
>> class is present. In a modular world, a modular application can use
>> isModulePresent method instead. This leads to another question that
>> module P should statically reference types from an optional module M;
>> replace the use of Class.forName if it was to eliminate static
>> dependency (this is the approach JDK uses).
> Directly using references to classes may cause verification failures
> because in order to verify class P;
> the Class being referenced must be resolved. Check with those most
> knowledgable about the verifier.
>>
>> Mandy
>
More information about the jigsaw-dev
mailing list