Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build with --release 8, or require builds to use JDK 8 #3990

Open
cpovirk opened this issue Aug 19, 2020 · 24 comments
Open

Build with --release 8, or require builds to use JDK 8 #3990

cpovirk opened this issue Aug 19, 2020 · 24 comments
Assignees
Labels
P3 package=general type=defect Bug, not working as expected

Comments

@cpovirk
Copy link
Member

cpovirk commented Aug 19, 2020

I discovered in protocolbuffers/protobuf#7827 (comment) that Animal Sniffer does not fail the build for dangerous covariant return types. This means that, if we build a Guava release with JDK 11 (which we probably will, if we haven't already!), it will contain references that don't work under JDK 8. We do in fact have such references.

Luckily, I do not see any additional such problems in the Android branch. (Presumably our internal Android tests have detected any possible problems so far.)

We should set this up before our next release or else be VERY VERY sure to use JDK 8 to build it.

@cpovirk cpovirk added package=general P2 type=debeta Request to remove something from @Beta labels Aug 19, 2020
@cpovirk cpovirk added this to the NEXT milestone Aug 19, 2020
@cpovirk
Copy link
Member Author

cpovirk commented Aug 19, 2020

Later, assuming that the implementation of GoogleCloudPlatform/cloud-opensource-java#1605 goes in, we should consider switching to the Linkage Checker Enforcer Rule.

@cpovirk
Copy link
Member Author

cpovirk commented Aug 19, 2020

Ah, but the Linkage Checker will check only against the JDK that you're using to build. So we're back to needing to require builds to use JDK 8. And all the Linkage Checker would be doing then is looking at dependencies (of which we have effectively none).

@cpovirk
Copy link
Member Author

cpovirk commented Aug 19, 2020

--release 8 is indeed intended to catch such problems, including the specific ones we'd see with ByteBuffer: jetty/jetty.project#3244 (comment)

@cpovirk
Copy link
Member Author

cpovirk commented Aug 19, 2020

As I just noted on the protobuf thread, it sounds like the best option is to require builds to be done with JDK 8. (It might also be OK to build with a newer JDK but with an older bootclasspath, but I'm not sure how well supported that is, since bootclasspath is on the way out. I gather that we're internally doing something along those lines with Bazel, but I don't know how easy it is to do the equivalent externally or with Maven.)

We could consider requiring JDK 8 only for release builds. That would make life easier for an average developer who wants to contribute to Guava (and might not have JDK 8 lying around). On the other hand, it might make it more confusing to reproduce actual problems. Maybe we'd want to support some kind of -DletMeUseMyOwnJdkIPromiseIAmNotDoingARelease override flag.

Hmm, and we have Travis building with various versions.... I wonder how long it will be until openjdk8 is no longer available there.

@cpovirk cpovirk added type=defect Bug, not working as expected and removed type=debeta Request to remove something from @Beta labels Aug 19, 2020
@cpovirk cpovirk self-assigned this Aug 19, 2020
@cpovirk
Copy link
Member Author

cpovirk commented Aug 20, 2020

(Certainly we at least want it to be possible to build and test with another JDK, since we want to verify that Guava works with new Java versions.)

@cpovirk
Copy link
Member Author

cpovirk commented Aug 20, 2020

Hmm, internally we're not going to be able to keep building with JDK 8 after our switchover. (And as established above, we can't just use --release.) So we should probably look at (a) wrapping all our calls to ByteBuffer methods that are changing and (b) writing a quick Error Prone check to ensure that we continue to do so.

Such a check, of course, would catch only the methods that we specifically program it to look for.

If we get things right internally, that should also make it possible to build with JDK 11 externally.

And building with JDK 11 is good for at least one more reason: Just as we currently use Unsafe conditionally, we'll want to use new APIs like VarHandle and @ReservedStackAccess conditionally. For that, we'll need to build with newer JDKs. It would be a shame not to have a way to make those improvements available publicly. [edit: Oh, but I guess that is what multi-release jars are for. We'd have to do some work to set them up, but it should be doable.]

We'll see if it's still straightforward to refer to Unsafe when building for JDK 11. Maybe we'll end up with a gross build setup that unpacks an old rt.jar and tries to put sun.misc.Unsafe on the classpath. Or maybe we'll end up running multiple separate javac invocations. Or maybe this will end up being easier under Bazel, since presumably external Bazel will support whatever we end up doing with internal Bazel. But if we're lucky, it will remain straightforward. [edit: Bazel still supports building with JDK8, but we might prefer not to rely on whatever build tools we use to support older JDKs for long.]

@cpovirk
Copy link
Member Author

cpovirk commented Aug 20, 2020

Hmm, and this is not the same thing, but when testing my fix for ByteBuffer when building with JDK 11, I noticed an error when running mvn clean install:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.1.0:jar (attach-docs) on project guava: MavenReportException: Error while generating Javadoc: Unable to find javadoc command: The environment variable JAVA_HOME is not correctly set. -> [Help 1]

It works fine if I set JAVA_HOME, but it's unfortunate that that's necessary. I will see if 3.2.0 works better.

@cpovirk
Copy link
Member Author

cpovirk commented Aug 20, 2020

(3.2.0 has the same problem.)

netdpb pushed a commit that referenced this issue Aug 21, 2020
…rns in Java 9+.

Doing so produces a jar that doesn't work under Java 8.

This CL addresses the currently existing problematic calls (by calling the methods on the supertype Buffer instead), but we should also add safeguards.

The normal solution to this general problem is to use --release, but doing so here is complicated.

For more information, see #3990

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=327654073
@cpovirk
Copy link
Member Author

cpovirk commented Aug 21, 2020

Ah, since we run our build and tests under JDK 11 with Travis, I guess we have evidence that that works, at least currently :)

netdpb pushed a commit that referenced this issue Aug 21, 2020
…rns in Java 9+.

Doing so produces a jar that doesn't work under Java 8.

This CL addresses the currently existing problematic calls (by calling the methods on the supertype Buffer instead), but we should also add safeguards.

The normal solution to this general problem is to use --release, but doing so here is complicated.

For more information, see #3990

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=327654073
@cpovirk cpovirk added P3 and removed P2 labels Aug 24, 2020
@cpovirk cpovirk removed this from the NEXT milestone Aug 24, 2020
@cpovirk
Copy link
Member Author

cpovirk commented Aug 24, 2020

406a4ea did enough that I'm no longer alarmed about this. Still, we'll want to do more before too long.

@cpovirk
Copy link
Member Author

cpovirk commented Sep 14, 2020

Some work on ClosingFuture to address https://travis-ci.org/github/google/guava/builds/726475379 reminds me that javac 8 probably has at least more bugs than javac 11 does.

@cpovirk
Copy link
Member Author

cpovirk commented Dec 17, 2020

We already have cases of the conditional use I described above. Specifically, we use APIs from higher than Java 6 in guava-android -- again, only conditionally, but --release 6 would still object:

@IgnoreJRERequirement // getChecked falls back to another implementation if necessary

@cpovirk
Copy link
Member Author

cpovirk commented Jan 20, 2021

Maybe we'll end up with a gross build setup that unpacks an old rt.jar and tries to put sun.misc.Unsafe on the classpath.

@cpovirk
Copy link
Member Author

cpovirk commented Feb 16, 2021

We can also consider using Unsafe through a MethodHandle instead of referring to it directly in code.

That said, that is an option only for the JRE, not for Android. That said, we less urgently need --release 8 for Android because Android builds work around the Buffer problem (as noted in passing here). So maybe we could just keep using Unsafe directly in the Android branch. But wait, no, because that branch should still be usable from the JRE. (And anyway, it would be nice to avoid having diffs between how we use Unsafe in each environment, even if hidden in a package-private UnsafeAccess class that we write, tweak for each flavor of Guava, and clone to every package that needs it.)

copybara-service bot pushed a commit that referenced this issue Sep 9, 2021
…m tests.

This doesn't fix a practical problem today.

What it does do is unblock us from adding checking (which will run in our internal builds) that will detect the main problems described in #3990.

RELNOTES=n/a
PiperOrigin-RevId: 395740030
@cpovirk
Copy link
Member Author

cpovirk commented Aug 16, 2022

(Building with JDK8 requires our newly adopted Error Prone setup to stick with an old version of Error Prone.)

[edit: And eamonnmcmanus mentions #5653 as a problem with using older-than-necessary versions of the JDK in general.]

@stephenspol
Copy link

Issue #6167 is related to Error Prone setup.

copybara-service bot pushed a commit that referenced this issue Oct 27, 2022
…nd make builds work with newer JDKs.

This should fix the error reported in #6217 (comment). I'm not sure if the Error Prone update was necessary for that or if only the `pom.xml` changes were. Still, it seems inevitable that we'll be forced to upgrade Error Prone eventually, and it's rarely a bad idea to update a plugin.

This change is progress toward building and testing under Java 17 (#5801)...

...which we apparently regressed at when we enabled Error Prone (#2484).

I've set this change up in a way that lets builds continue to work under JDK8 (which is potentially useful for #3990 or for anyone building Guava manually with an old JDK), albeit with Error Prone disabled.

RELNOTES=n/a
PiperOrigin-RevId: 484299394
copybara-service bot pushed a commit that referenced this issue Nov 3, 2022
This has some effects on us as we develop Guava, but it doesn't affect end users.

Specifically:

- When we build Guava with JDK8, we now have to disable Error Prone. (Again, users can still use Guava with JDK8, including with Error Prone. The effect is limited to people who are developing Guava.)
- We can now successfully build Guava with Error Prone under more recent JDKs. That is, this change should fix the error reported in #6217 (comment). (I'm not sure if the Error Prone update was necessary for that or if only the other `pom.xml` changes were. Still, it seems inevitable that we'll be forced to upgrade Error Prone eventually, and it's rarely a bad idea to update a plugin.)

This change is progress toward building and testing under Java 17 (#5801)...

...which we apparently regressed at when we enabled Error Prone (#2484).

Oddly, it seems that part of our existing Error Prone setup is _required_ to continue building Guava under JDK8. (Such builds are potentially useful for #3990 or for anyone building Guava manually with an old JDK.) That's the case even though we're now disabling Error Prone for those builds.

Again, all these changes affect only people who are developing Guava, not end users.

RELNOTES=n/a
PiperOrigin-RevId: 484299394
copybara-service bot pushed a commit that referenced this issue Nov 3, 2022
This has some effects on us as we develop Guava, but it doesn't affect end users.

Specifically:

- When we build Guava with JDK8, we now have to disable Error Prone. (Again, users can still use Guava with JDK8, including with Error Prone. The effect is limited to people who are developing Guava.)
- We can now successfully build Guava with Error Prone under more recent JDKs. That is, this change should fix the error reported in #6217 (comment). (I'm not sure if the Error Prone update was necessary for that or if only the other `pom.xml` changes were. Still, it seems inevitable that we'll be forced to upgrade Error Prone eventually, and it's rarely a bad idea to update a plugin.)

This change is progress toward building and testing under Java 17 (#5801)...

...which we apparently regressed at when we enabled Error Prone (#2484).

Oddly, it seems that part of our existing Error Prone setup is _required_ to continue building Guava under JDK8. (Such builds are potentially useful for #3990 or for anyone building Guava manually with an old JDK.) That's the case even though we're now disabling Error Prone for those builds.

Again, all these changes affect only people who are developing Guava, not end users.

RELNOTES=n/a
PiperOrigin-RevId: 485770768
copybara-service bot pushed a commit that referenced this issue Feb 23, 2023
…hecker) for Maven builds.

We already have it on for our builds inside Google, but Maven checking provides an additional line of defense against #3990.

Because this CL enables checking for our _tests_, too (which is hard not to do, as discussed in the existing `pom.xml` comment about NullArgumentForNonNullParameter), I had to edit a couple benchmarks to avoid using what are _in a limited sense_ "Java 9+ APIs." They wouldn't be practical problems, though.

RELNOTES=n/a
PiperOrigin-RevId: 511801224
copybara-service bot pushed a commit that referenced this issue Feb 23, 2023
…hecker) for Maven builds.

We already have it on for our builds inside Google, but Maven checking provides an additional line of defense against #3990.

Because this CL enables checking for our _tests_, too (which is hard not to do, as discussed in the existing `pom.xml` comment about NullArgumentForNonNullParameter), I had to edit a couple benchmarks to avoid using what are _in a limited sense_ "Java 9+ APIs." They wouldn't be practical problems, though.

RELNOTES=n/a
PiperOrigin-RevId: 511830560
@cpovirk
Copy link
Member Author

cpovirk commented Feb 24, 2023

I am not quite ready to declare absolute victory after #6334, but that helps.

I note that we don't run Error Prone (and thus Java8ApiChecker) under Java versions below 11 (#6230, #6243), but that's OK:

  • When we build with JDK8, we know that we're compatible with JDK9.
  • We can't build with JDK9 or JDK10 at all.

Other things that could help:

@cpovirk
Copy link
Member Author

cpovirk commented May 10, 2023

I mentioned this in #5457 (comment) earlier today, but: Error Prone just set up testing based on Maven toolchains. As discussed above, that would be useful for us here.

copybara-service bot pushed a commit that referenced this issue Jun 13, 2023
This is the first use of a Java 9 API in Guava, but we use the API only when it's available, so we maintain compatibility with Java 8. Use of Java 9 APIs is relevant to #6549 and #3990 (and also mojohaus/animal-sniffer#67).

I didn't make the same change for `guava-android`, which [will add `java.util.zip.CRC32C` in API Level 34](https://developer.android.com/reference/java/util/zip/CRC32C). I don't know if Android is providing similar performance improvements, so it might not even matter. But even if I wanted to do it, I can't with my current approach, which relies on `MethodHandle`—unless I want to make even the usage of `MethodHandle` conditional on a reflective check :)

RELNOTES=`hash`: Enhanced `crc32c()` to use Java's hardware-accelerated implementation where available.
PiperOrigin-RevId: 539722059
copybara-service bot pushed a commit that referenced this issue Jun 13, 2023
This is the first use of a Java 9 API in Guava, but we use the API only when it's available, so we maintain compatibility with Java 8. Use of Java 9 APIs is relevant to #6549 and #3990 (and also mojohaus/animal-sniffer#67).

I didn't make the same change for `guava-android`, which [will add `java.util.zip.CRC32C` in API Level 34](https://developer.android.com/reference/java/util/zip/CRC32C). I don't know if Android is providing similar performance improvements, so it might not even matter. But even if I wanted to do it, I can't with my current approach, which relies on `MethodHandle`—unless I want to make even the usage of `MethodHandle` conditional on a reflective check :)

RELNOTES=`hash`: Enhanced `crc32c()` to use Java's hardware-accelerated implementation where available.
PiperOrigin-RevId: 539722059
copybara-service bot pushed a commit that referenced this issue Jun 13, 2023
This is the first use of a Java 9 API in Guava, but we use the API only when it's available, so we maintain compatibility with Java 8. Use of Java 9 APIs is relevant to #6549 and #3990 (and also mojohaus/animal-sniffer#67).

I didn't make the same change for `guava-android`, which [will add `java.util.zip.CRC32C` in API Level 34](https://developer.android.com/reference/java/util/zip/CRC32C). I don't know if Android is providing similar performance improvements, so it might not even matter. But even if I wanted to do it, I can't with my current approach, which relies on `MethodHandle`—unless I want to make even the usage of `MethodHandle` conditional on a reflective check :)

RELNOTES=`hash`: Enhanced `crc32c()` to use Java's hardware-accelerated implementation where available.
PiperOrigin-RevId: 539722059
copybara-service bot pushed a commit that referenced this issue Jun 13, 2023
This is the first use of a Java 9 API in Guava, but we use the API only when it's available, so we maintain compatibility with Java 8. Use of Java 9 APIs is relevant to #6549 and #3990 (and also mojohaus/animal-sniffer#67).

I didn't make the same change for `guava-android`, which [will add `java.util.zip.CRC32C` in API Level 34](https://developer.android.com/reference/java/util/zip/CRC32C). I don't know if Android is providing similar performance improvements, so it might not even matter. But even if I wanted to do it, I can't with my current approach, which relies on `MethodHandle`—unless I want to make even the usage of `MethodHandle` conditional on a reflective check :)

RELNOTES=`hash`: Enhanced `crc32c()` to use Java's hardware-accelerated implementation where available.
PiperOrigin-RevId: 539983316
@cpovirk
Copy link
Member Author

cpovirk commented Sep 15, 2023

We should set this up before our next release or else be VERY VERY sure to use JDK 8 to build it.

There are many downsides to the "be very very sure" approach, but one that's only recently occurred to me is this: Other people may build their own copies of Guava for internal use (to fulfill security requirements, to apply patches, to insert debugging printlns...). It would be nice if they didn't encounter any unpleasant surprises when they switch from a prebuilt Guava to a version that they build locally—and potentially build with a different version of javac.

(not that we are currently relying on our builds to be built with JDK 8, but the JDK developers have the right to make another ByteBuffer-like change in any future release)

@tbroyer
Copy link

tbroyer commented Sep 20, 2023

Coming here from google/auto#1596

Fwiw, that "animal sniffer doesn't detect everything" issue has been known for almost a decade (and the underlying issue for much more: there's a reason why javac warns when using -source without -bootclasspath since jdk 7 😉): see https://www.cloudbees.com/blog/beware-sirens-target-call and https://www.draconianoverlord.com/2014/04/01/jdk-1.8/1.7-compatibility-gotcha.html/ (and that was the reason I was delighted by the --release addition to the JDK: now I could safely cross-compile! …of course because I don't personally need any --add-opens/--add-exports, or Unsafe 😅)

@cpovirk
Copy link
Member Author

cpovirk commented Sep 20, 2023

The bizarre thing about the ByteBuffer Animal Sniffer problem in particular is that the Animal Sniffer developers added code whose explicit and only purpose was to not error out when it detects this dangerous thing that it was at that point already erroring out for: If the developers had just left things alone 10 years ago, Animal Sniffer would have continued to detect the ByteBuffer problem. Aside from that, we've found Animal Sniffer to be a decent defense against -source without -bootclasspath. (If there are additional problems with it, then I would be, as you can probably guess, all ears :) I do know of at least a few.... [edit: I dug up the issue we have about this, and I see the Iterator.remove issue you linked to, which I'd forgotten about :)])

@cpovirk
Copy link
Member Author

cpovirk commented Sep 21, 2023

Sorry, I was a bit distracted by my Animal Sniffer grouchiness yesterday, and I didn't really speak much to your point, nor think things through a whole lot in general.

If I had any point yesterday, it would be: The combination of Animal Sniffer and an additional build with Java 8 has worked pretty well for us, except for the ByteBuffer case I was ranting about. But that's a rather large exception. And, as you say, even if Animal Sniffer were to fix the ByteBuffer case, Animal Sniffer remains insufficient on its own. (We hit the Animal Sniffer issue from the CloudBees post in Flogger, IIRC.)

For our projects that don't even use Animal Sniffer yet, I definitely would want to pursue the toolchain-based approach (rather than Animal Sniffer) if we were to decide to pursue anything at all. Our current approach in Guava (and Truth and maybe others) is Doing It Wrong (though we're likely to be OK in practice, given that we've thrown yet more testing thrown into the mix).

Your comment also reminds me that, while I found that we could add Unsafe to the classpath during a --release 8 build, I wouldn't want to assume that that's a permanent solution: Might the module-related enforcement of --release 9 and higher interfere with sticking classes into sun.misc? Maybe, maybe not. But I'd want to test before putting that approach in place. (Not that I expect to play with --release for Guava in the near future.)

@cpovirk
Copy link
Member Author

cpovirk commented Nov 14, 2023

We're also hearing that Android desugaring is more reliable when libraries are compiled against android.jar or at least against a relatively similar JDK. As we build against newer and newer versions of the JDK API (by using newer and newer JDKs without using --release), we are increasingly likely to see problems there—like an Android problem similar to the problem reported by Animal Sniffer in #6830.

@cpovirk
Copy link
Member Author

cpovirk commented Nov 14, 2023

(Ideally we'd have a test that runs D8/R8 over guava-android, too. We run such tests in our internal build, but as I noted in 464bedf, we have reason to believe that we could see different errors internally and externally, even before accounting for the differences in the internal and external copies of Guava. I wonder if that would get easier with Bazel (#2850).)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P3 package=general type=defect Bug, not working as expected
Projects
None yet
Development

No branches or pull requests

3 participants