feat(FeatureClassLoader): support class loading of Java 9+ by bender316 ยท Pull Request #426 ยท diffplug/spotless
With Java 9 class loading was changed in that way that the bootstrap class loader does not see all classes anymore.
In Java 9+ the platform classloader needs to be used.
A good explanation can be found at http://java9.wtf/class-loading/
fixes #206
It would be great if this fix can be released ASAP as it stalls our migration to Java 11. I'm honestly quite surprised that not more people are affected by this.
With Java 9 class loading was changed in that way that the bootstrap class loader does not see all classes anymore. In Java 9+ the platform classloader needs to be used. A good explanation can be found at http://java9.wtf/class-loading/ fixes #206
it stalls our migration to Java 11
If you comment out freshmark, does all of the rest work? Is it only freshmark which is blocked?
I haven't ventured past Java 8 myself yet, so I'm going to rely on the expertise of the rest of the Spotless community to code review this. Looks like spotbugs is upset, run spotbugsMain on your box to see what it's upset about.
@bender316 I'm also a bit surprised that it's taken this long for Java 9+ related issues to appear with Spotless, because I've been using Spotless for Gradle on a Java 11 project without problems for a while now. ๐ค
I'll see if I can find the time to review this PR this weekend. :)
If you comment out freshmark, does all of the rest work? Is it only freshmark which is blocked?
Yes. It's not spotless in general which is affected but single formatters. Since we're only using java, groovy and freshmark formatters I can't tell for other formatters.
freshmark breaks because it uses ScriptEngine and javax.script package does not get picked up by the bootstrap classloader anymore.
I think @nedtwigg's review of this PR is great!
@bender316 I personally don't have anything else to add, and if anything I'm probably unqualified to review this PR because even after reading http://java9.wtf/class-loading/, I'm a bit confused as to how we can get references to all the classes in the Java standard library even though they were put into different modules as of Java 9. Is it because we (Spotless) or Gradle uses the classpath rather than the module path?
But regardless, from my point of view, if you're able to apply @nedtwigg's comment, then this PR receives my ๐. :)
I'm a bit confused as to how we can get references to all the classes in the Java standard library even though they were put into different modules as of Java 9. Is it because we (Spotless) or Gradle uses the classpath rather than the module path?
@jbduncan It's because the FeatureClassLoader extends URLClassLoader. If URLClassLoader has no set parent it uses the bootstrap classloader. Prior to Java 9 the bootstrap classloader had access to all classes. Starting with Java 9 it has access to a reduces number of classes. Hence we need to use the platform classloader which can access all classes.
Ok, I added a simple JavaVersion class which parses the version string and provides a getter for the major version. In FeatureClassLoader there is now a check if the version is >= 9 and then calls the getPlatformClassLoader method
|
|
||
| static { | ||
| JAVA_VERSION = System.getProperty("java.version"); | ||
| final String[] versionStrings = JAVA_VERSION.split("\\."); |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we write like,
double version = Double.parseDouble(System.getProperty("java.specification.version")); if(version > 1.8) { //Do something } else { //Do something }
Just curious, why? and why not? It eliminates the need of this Utility class.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is Double.parseDouble("1.8.0")?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like java.specification.version just returns 1.x or 11 (in cases of new versioning) and not the full version. I didn't know about this property. So IMO we could use this and get rid of the JavaVersion class.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will switch to the proposal above and remove the JavaVersion class.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks very much! This looks great, two very small nits and I'm ready to merge.
Hopefully the last push ๐
I testet it with
openjdk-1.8.0.171 (OpenJDK)
jdk-9.0.4+11 (AdoptOpenJDK)
jdk-11.0.4+11 (AdoptOpenJDK)
So at least it supports older versions and the latests LTS ones.
Hopefully the last push ๐
I testet it with
openjdk-1.8.0.171 (OpenJDK)
jdk-9.0.4+11 (AdoptOpenJDK)
jdk-11.0.4+11 (AdoptOpenJDK)So at least it supports older versions and the latests LTS ones.
๐ :) Looks more clean now!!
Thanks very much for this fix, @bender316. I'll release by Monday at the latest.
Thanks very much for this fix, @bender316. I'll release by Monday at the latest.
Sounds good. Thank you all for this PR review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters