Project Jigsaw: Language changes for Modules
2009/2/3
Definitions
A module is a set of types in one or more named packages.
The members of a module are all the class and interface types declared in all the compilation units of the module.
A module identity is a structure M@V, where M is the name of the module and V is the version of the module. The Java language assigns no meaning to the version of a module.
A module compilation unit is a source file named module-info.java.
A package compilation unit is a source file named package-info.java.
Language syntax
Example
import P.*;
@Foo
module M1@1.0 provides M2@2.0, M3@3.0 {
requires M4@4.0, M5@5.0;
permits M6;
}
Grammar
CompilationUnit:
ImportDeclarations_opt ModuleDeclaration_opt PackageDeclaration_opt ImportDeclarations_opt TypeDeclarations_opt
ModuleDeclaration:
Annotations_opt 'module' RestOfModuleDeclaration
RestOfModuleDeclaration:
QualifiedIdentifier ';'
ModuleId ModuleProvides_opt '{' { ModuleMetadata } '}'
ModuleProvides:
'provides' ModuleId {',' ModuleId}_opt
ModuleMetadata:
ModuleRequires
ModulePermits
ModuleRequires:
'requires' {ModuleRequiresModifier}_opt ModuleId {',' ModuleId}_opt ';'
ModuleRequiresModifier:
'optional'
'private'
'local'
ModulePermits:
'permits' QualifiedIdentifier {',' QualifiedIdentifier}_opt ';'
ModuleId:
QualifiedIdentifier ModuleVersion_opt
ModuleVersion:
'@' Space_opt ModuleVersionStart ModuleVersionPart*
'@' Space_opt StringLiteral
ModuleVersionStart:
digit
'['
'('
ModuleVersionPart:
InputCharacter but not FF, Space, Tab, '"', '\'', '\\', ',', ';'
// InputCharacter is any UnicodeInputCharacter except CR and LF
Modifier:
Annotation
'public'
'module'
'protected'
'private'
'static'
...
Language semantics
Module membership
A module declaration in a compilation unit specifies the name of the module to which types in the compilation unit belong:
module M;
package P;
public class Foo {...}
module is a restricted keyword in the ModuleMembership and
MethodOrFieldDecl productions of a CompilationUnit.
(A restricted keyword is a character sequence that is an identifier except where it appears as a terminal in a specific production, whereupon the terminal itself is defined as a keyword. Restricted keywords permit character sequences that were formerly classified as identifiers to be introduced into the syntactic grammar of the Java programming language as if they are keywords in very limited contexts. This overcomes the problem that introducing keywords into the syntactic grammar otherwise makes identifiers with the same character sequences illegal. There must be no ambiguity between a restricted keyword and an identifier anywhere in the grammar.)
A module name can be simple or qualified. There is no obscuring between module names and other names. This means there is no prohibition against a module having the same name as any package.
If a compilation unit declared in package P does not contain a module declaration, then the compilation unit belongs to the module declared in the package compilation unit for P, or to the unnamed module if either no such package compilation unit exists or it exists without a module declaration. All types declared in the compilation unit are members of the module to which the compilation unit belongs.
For example, a compilation unit:
com/foo/bar/C.java
which does not contain a module declaration will have its types be members of the module com.foo.bar iff com/foo/bar/package-info.java exists and declares the com.foo.bar module; or a member of the unnamed module otherwise.
If none of the observable compilation units in a package (including the package compilation unit) contain a module declaration, then the host system may optionally treat all the compilation units as if they contained declarations of a module known to the host system.
This allows a Java compiler invoked from the command line to support parameters which associate a package with a module, even if no compilation units in the package contain a module declaration.
Note that a type is a member of the unnamed module if it is a) declared in a compilation unit with a package declaration but no module declaration, and b) the relevant package compilation unit (if it exists) has no module declaration.
A type in an unnamed package is a member of the unnamed module. It is a compile-time error if a compilation unit in an unnamed package belongs to a named module.
The host system must enforce the restriction that it is a compile-time error if an observable compilation unit C belongs to a module which is not consistent with either:
- the module of any other observable compilation unit D, in the same package as C, to which code in C refers; or
- the module to which the package compilation unit for C's package belongs (if such a compilation unit exists); or
- the module to which the module compilation unit for C's module belongs (if such a compilation unit exists).
Comment: All explicit module declarations in the observable compilation units for a package should be consistent, but we do not want to require a compiler to check consistency across every observable compilation unit every time one is re-compiled.
Module accessibility
If a class or interface type is declared public,
then it may be accessed by any code, provided that the compilation
unit in which it is declared is observable.
If a class or interface type is declared module,
then it may be accessed only from within the module in which it is
declared.
If a top level class or interface type is not declared
public or module, then it may be accessed
only from within the package in which it is declared.
A member (class, interface, field, or method) of a reference
(class, interface, or array) type or a constructor of a class type
is accessible only if the type is accessible and the member or
constructor is declared to permit access: - If the member or
constructor is declared public, then access is
permitted. - If the member or constructor is declared
module, then access is permitted only from within the
module containing the class in which the module member or
constructor is declared.
Module annotations
Annotations may be used on module declarations, with the restriction that at most one annotated module declaration is permitted for a given module. The sole annotated module declaration, if it exists, is placed in a compilation unit known as the module compilation unit. When packages are stored on a filesystem, the module compilation unit is a file called module-info.java. This file should be stored in a directory corresponding to the module name.
The restricted keyword module in a module
declaration in a module compilation unit may optionally be preceded
by annotation modifiers. If an annotation a on a module declaration
corresponds to an annotation type T, and T has a (meta-)annotation
m that corresponds to annotation.Target, then m must have an
element whose value is java.lang.annotation.ElementType.MODULE, or
a compile-time error occurs.
The host system must compile a non-empty module compilation unit if it contains at least a module declaration. It is a compile-time error if a module compilation unit does not contain a module declaration, or if it contains at least one type declaration without a package declaration.
Module metadata
The module declaration in a module compilation unit may contain metadata that expresses the dependencies of the module and any aliases by which the module is known:
module M provides P {
requires N;
permits L;
}
In M's metadata, requires N denotes a dependency of
module M on module N. permits L denotes that module L
may have a dependency on module M, and that no other module is
permitted to have a dependency on module M. If a module does not
have any permits clauses in its metadata, then any
module may have a dependency on it.
A module name may appear as an operand in at most one
requires clause and at most one permits
clause of a module compilation unit.
All public types in a module are observable to all types in the module. The host system must use a module's dependencies to determine which public types not in the module are observable to the types in the module. If public type T is not in module M, then T is observable to any type in M if:
- the host system can determine a module N that contains or re-exports T, and
- M has a dependency on N, and
- N permits M to have a dependency on N.
A module M re-exports a type T if:
- T is not a type that belongs to M but any type in M can observe T, and
- M's dependency on the module from which T is observable is not
marked
privatein M's metadata.
If a type T belongs to module M and is also observable from a module on which M has a dependency, then the Java programming language imposes no preference on which T should be used. However, the host system should choose which T to make observable in M and use it consistently.
The Java programming language imposes no ordering on the dependencies denoted in M's metadata. If M has a dependency on N which contains T, and M also has a dependency on O which re-exports T, then the host system is responsible for choosing either N or O as the module which makes T observable to M.
The optional modifier on a dependency indicates
that the host system must not give an error if it attempts to use
the module whose name appears in the dependency.
The local modifier on a normal dependency indicates
to the host system that the target module of the dependency must
have its types loaded with the same defining classloader as types
in the module with the dependency. If local is not
present, then the host system may choose an arbitrary defining
classloader for types of the target module.
The clause provides P indicates that a dependency
on module P by some other module may be satisfied by module M.

