3

In the JDK-8, we could compile our changed java.lang classes and reconstruct the rt.jar. Then we could overwrite java.lang classfiles by augmenting the bootclasspath with -Xbootclasspath:<yourpathto>/rt.jar. Doing this, we could for example make java.lang.Integer be non-final for testing purposes.

In JDK-11, this is different. Patching is done via --patch-modules and I can't get it to work. I have done the following:

  1. Remove the final modifier and recompiled the java.base module from the openjdk-11 source
  2. Added the --patch-module java.base=<path-to-my-compiled-java.base-directory>
  3. It still fails on error: cannot inherit from final Integer. Possibly we can't overwrite the class declarations of JDK source files anymore? That would be strange.
  4. I've also tried adding these classfiles to a jar and tried to pass all possible root directories to the --patch-module argument
  5. I've tried removing the module package-info.class from the compiled java.base directory and tried explicitly adding java.base.java.lang.Integer with --add-opens

The docs aren't really clear on this particular usage.

The entire javac command from maven (I have tried both javac and the maven-compiler-plugin):

javac -d ./target/classes -classpath <classpathfiles> -sourcepath <sourcefiles> -s ./target/generated-sources/annotations -g -nowarn -target 11 -source 11 -encoding UTF-8 --patch-module=java.base=../runtimejar/mods/src/java.base -Xplugin:Manifold

(Shortened path names etc. for readability)

What am I missing here? Why can't I modify java.base/java.lang.Integer like this?

MGG
  • 43
  • 7
  • Did you try using `--patch-module java.base=../runtimejar/mods/src \ ../runtimejar/mods/src/java.base/java/lang/Integer.java`? – Naman Aug 15 '20 at 00:35
  • @Naman, I just did, still get the same `error: cannot inherit from final Integer`. Shouldn't we patch modules with compiled .class files? – MGG Aug 15 '20 at 07:56
  • If you really want to change JDK classes you may better use the sources of JDK, modify it and build your own JDK. You should also consider that there may be better, cleaner ways to achieve what you want instead of modifying `Integer`. – Robert Aug 15 '20 at 08:56
  • Remove the `-target` command line parameter. – Johannes Kuhn Aug 15 '20 at 13:30

1 Answers1

3

The example from Project Jigsaw models your use-case. Note the use of --patch-module for both javac and java.

--patch-module

Developers that checkout java.util.concurrent classes from Doug Lea's CVS will be used to compiling the source files and deploying those classes with -Xbootclasspath/p.

-Xbootclasspath/p has been removed, its module replacement is the option --patch-module to override classes in a module. It can also be used to augment the contents of module. The --patch-module option is also supported by javac to compile code "as if" part of the module.

Here's an example that compiles a new version of java.util.concurrent.ConcurrentHashMap and uses it at run-time:

    javac --patch-module java.base=src -d mypatches/java.base \
        src/java.base/java/util/concurrent/ConcurrentHashMap.java

    java --patch-module java.base=mypatches/java.base ...

Check that your sourcepath aligns with your --patch-module directory i.e., is there a file src/java.base/java/lang/Integar.java and is it in your sourcepath?

Update

Here is a sample project that demonstrates how to shadow java.lang.Integer: https://dl.dropbox.com/s/6swet2k89vukxbm/patch.zip

Compile:

javac --patch-module java.base=src -d mypatches/java.base src/java.base/java/lang/Integer.java
javac --patch-module java.base=mypatches/java.base -d target src/main/java/com/example/MyInteger.java src/main/java/com/example/RunMe.java

Run:

java --patch-module java.base=mypatches/java.base -classpath target com.example.RunMe
Scott
  • 949
  • 9
  • 14
  • I've seen the example from Jigsaw, I'm a bit lost on how to translate it to my use-case properly. I want to compile my project with a patched `java.base.java.lang.Integer`. The example from Jigsaw only seems to compile the `ConcurrentHashMap`? I also need to compile `javac` with a patched `java.base`. I need to use the new patched `java.lang.Integer` at compile-time as well. – MGG Aug 15 '20 at 08:44
  • Just to be clear you are not making an Integer class in package java.base.java.lang, right? – Scott Aug 15 '20 at 08:52
  • No, my project doesn't have a java.base.java.lang.Integer.java file. I want to produce similar behaviour to adding a modified `rt.jar` to the bootclasspath. I need to compile and run my project with a patched `java.base.java.lang.Integer` that isn't final. – MGG Aug 15 '20 at 08:57
  • 1
    @MGG Just so you know, calling it `java.base.java.lang.Integer` is confusing. That implies the _package_ name is `java.base.java.lang`. It would be better to just say something like "the `java.lang.Integer` class from the `java.base` module" or do what stack traces do and use `java.base/java.lang.Integer`. You don't even necessarily have to mention the module since there can only be one `java.lang.Integer` due to the module system prohibiting split packages (and the classes in the `java.base` module, especially those in the `java.lang` package, are widely known). – Slaw Aug 15 '20 at 10:54
  • @MGG I've updated my post to include a simple example that demonstrates how to shadow java.lang.Integer with --patch-module. – Scott Aug 15 '20 at 22:21
  • Great. thank you! This is what I was looking for. I've found the culprit, it doesn't work when I use the compiler plugin `-Xplugin:Manifold`. Otherwise it seems to work finely. Maybe because this loads integer again or something in that direction.. – MGG Aug 16 '20 at 12:09
  • 1
    @MGG No problem. Thanks for posting the issue with Manifold, I've logged issue https://github.com/manifold-systems/manifold/issues/209 which will be fixed in the next release coming later this week. – Scott Aug 17 '20 at 07:13
  • 1
    @MGG A “`java.lang.Integer` that isn’t final” sounds you are planning to bring yourself into deep trouble… – Holger Aug 17 '20 at 12:49