Description
Given these equivalent Scala and Java sources, and compilers running on JDK 17:
$ cat Main.scala
import jdk.jfr.internal.Repository
class Main {}
$ cat Main.java
import jdk.jfr.internal.Repository;
public class Main {}
$ java -version
java version "17.0.11" 2024-04-16 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 17.0.11+7.1 (build 17.0.11+7-LTS-jvmci-23.0-b34)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.11+7.1 (build 17.0.11+7-LTS-jvmci-23.0-b34, mixed mode, sharing)
javac does not allow the use of the the internal API, with or without an explicit --release 17
because it always limits access based on modules:
$ javac Main.java
Main.java:1: error: package jdk.jfr.internal is not visible
import jdk.jfr.internal.Repository;
^
(package jdk.jfr.internal is declared in module jdk.jfr, which does not export it)
1 error
$ javac --release 17 Main.java
Main.java:1: error: package jdk.jfr.internal is not visible
import jdk.jfr.internal.Repository;
^
(package jdk.jfr.internal is declared in module jdk.jfr, which does not export it)
1 error
Without --release
the module can be made accessible with --add-exports
but this is rejected when used with --release
(whether the requested version matches the current JDK version or not):
$ javac --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java
$ javac --release 17 --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java
error: exporting a package from system module jdk.jfr is not allowed with --release
1 error
$ javac --release 11 --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java
error: exporting a package from system module jdk.jfr is not allowed with --release
1 error
Instead of using --release
it is possible to manually set both -source
and -target
version and override the system module path (the module equivalent of the bootclasspath) to get the same effect as --release
while allowing the use of --add-exports
:
$ javac -source 11 -target 11 --system /Users/stefan.zeiger/.sdkman/candidates/java/11-zulu-local Main.java --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED
scalac has several inconsistencies with this scheme:
-
By default scalac is not module-aware. It allows access to private APIs without warnings or errors:
$ scalac Main.scala
-
Setting an explicit release version enforces module access but only if the version is lower than the current JDK version, otherwise it is treated the same as not using modules:
$ scalac -release:17 Main.scala $ scalac -release:11 Main.scala Main.scala:1: error: object internal is not a member of package jdk.jfr import jdk.jfr.internal.Repository ^ 1 error
-
There are no equivalents of
--add-exports
and--system
and thus no way to target an older release without enforcing strict module access.
(This is about Scala 2; I tested it with 2.13.14 but AFAICT there are no changes in this area in any recent 2.13 or 2.12 version since the feature was added; I have not tried it with Scala 3)