"Module local" access behaviour in Java 9

A public element (i.e., a class, interface, method, or field) in a non-exported package is, in effect, “module local.” It will be accessible to all other code in the module, but not from outside the module.

There is no way to declare a module-local element in an exported package. A public element of an exported package is accessible from outside the module, a package-private element is still package-private, and there’s no element-level access mode between these two modes. We could define a new such mode but we’ve seen few compelling use cases for it and, moreover, implementing modular access control in the JVM at a granularity finer than that of exported packages would impose significant performance costs.


Short Answer

It can be helpful when there are some elements in module which are essentially public for this module, but shouldn't be accessible outside this module.

That is not possible. (With means of the module system alone - there is a workaround.)

Long Answer

The explanation lies within the term Accessibility:

The Java compiler and virtual machine consider the public types in a package in one module to be accessible by code in some other module only when the first module is readable by the second module, in the sense defined above, and the first module exports that package. [...]

A type referenced across module boundaries that is not accessible in this way is unusable in the same way that a private method or field is unusable: Any attempt to use it will cause an error to be reported by the compiler, or an IllegalAccessError to be thrown by the Java virtual machine, or an IllegalAccessException to be thrown by the reflective run-time APIs. [...]

A method or field referenced across module boundaries is accessible if its enclosing type is accessible, in this sense, and if the declaration of the member itself also allows access.

While there are different ways exactly how and to whom a package can be exported, once the compiler/JVM deems a type accessible no additional mechanism applies. Its members are as accessible as they were before Jigsaw.

This means that there is no way to have an accessible type's members visible within the module (that would require public) but not outside of it (because a public member of an accessible type is accessible).

Workaround

So is any other possibility to do it in future Java 9?

Yes. :)

You can have a public interface Global in an exported package that defines the methods you want to export to the world. Then have either an interface or a class Local extend Global and add all the members you want. Key is that Local must not be in an exported package!

Now if your module's API only returns Global-s but never accepts them as a method argument, you're good to go. Just make sure that internally you always use - and maybe cast to - Local.

If you also accept Global-s you have to clearly document that these can only ever be instances your API returned (i.e. the user is not allowed to create her own implementation). This might sound prohibitive but if you think hard about your original request, it would have the same characteristics.