Optional Module Dependency

Roger Riggs Roger.Riggs at Oracle.com
Thu Jun 9 07:59:50 PDT 2011


Hi Mandy,


On 6/8/11 5:37 PM, Mandy Chung wrote:
>  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 semantics need to be strong and useful (or the name of the 
annotation should be
changed to reflect a purely informative function).
As is the annotation may even be inconsistent with the declarations in 
the module-info file.

The annotation as presently defined is optional;  the behavior of the 
compiler and
runtime is the same whether it is included or not.  I don't expect it 
will be used
except where documentation is important.
>
>>
>> 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.
So the developer will need to code two separate calls in a compound 
expression
to achieve the needed result. It is inefficient and does not adequately 
expressive
the requirement in the code.
>
>> 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.
Clear from what?  Will each module have a separate specification that 
exhaustively
lists the included classes?  Will compatibility tests verify that a 
module contains
the public/protected classes that are required?  Signature tests need to be
at the module level; not the whole platform.

> 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.
The tools available to vendors and library creators should be as powerful
and expressive as those for the system.
>
>> 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.
Where is the alias concept described?
> 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?
A notification system  (such as Growl) will consist of a library that 
can operate
in many different environments and will want to dynamically take advantage
of the available notification mechanisms.   In some cases, it will be 
only non-ui
logging, in other cases, there may be a Swing UI present or a JavaFX UI 
present.
Non-system libraries need to able to make the same intelligent choices
about which modules are present and which classes are available.
>
>>
>> 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.
I was explicit that the test needed to be lightweight and not have the side
effect of loading the class.  Class.forName does not meet the requirement.

The developer may want to test the configuration before selecting which
mechanism to use.  It will also help startup/first use performance to defer
loading of the class until it is 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?
I'll think about it. If the dependencies in the module-info.java file 
were tagged, that could
provide the hook.
>
>> 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.
I'm not sure that's the best example, Properties has the dependencies on 
XML, not the application,
the requirement for jdk.jaxp should be in the java.util module-info.java 
file.

Unless this is reflecting to the application level that Properties has 
optional behavior
and the application is responsible for resolving whether it is required 
or not.
>
> The developer of the optional methods will be responsible to make sure
> a ModuleNotPresentException is thrown if the requir*(ed)* module is not
> present.
I'm looking for compiler support for developer who have to write 
"optional" methods.
Should ModuleNotPresentException should be documented for the method?
Strictly speaking it does not need a throws clause because it is a 
runtime exception
but it would useful and consistent documentation.
>
>>
>> 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.
Thanks, this would be most useful.
>
>> 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, Roger

>
>> 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