JEP draft: Prepare to Restrict The Use of JNI

Ron Pressler ron.pressler at oracle.com
Tue Aug 29 10:26:10 UTC 2023



> On 28 Aug 2023, at 23:30, Ryan Schmitt <rschmitt at apache.org> wrote:
> 
> > JNI is the same; we're not taking it away, but we're helping the user be aware of when a library is putting the integrity of the application at risk, so that they have the ability to make a judgement call on whether they are willing to trust that library.
> 
> My concern is that this is going to be GDPR cookie banners all over again, or Proposition 65 warnings ("this Java application contains chemicals known to the state of California to cause cancer"). Justifications like "user awareness" and "conscious opt-in" strike me as weak when human factors like alarm fatigue [1] are considered. The JEP states that "the last few years have proven that the vast majority of code does not require breaking encapsulation," and I think that's factual but not truthful: almost all of the real-world JDK8 applications I've seen needed flags like `--add-opens` in order to upgrade to JDK11+, and to the best of my knowledge the use of JNI is also near-universal, at least at my company. Is integrity-by-default still worth doing if *every* real-world Java application requires these flags?
> 
> I suspect the answer is: yes, but not for reasons of informed user consent. Rather, the goal here is to incentivize the ecosystem to reduce its dependence on JNI and other integrity-breaking features, similar to what Windows Vista did by introducing UAC [2]. In fact, the JEP frankly discloses this intention:
> 
> > Because deep dependency trees are common, the chances are high that an application would unknowingly depend on an encapsulation-breaking library. Consequently, if applications had to opt into strong encapsulation, few would be able to do so. The platform must, therefore, exert pressure on the ecosystem to minimize the proliferation of libraries that bypass strong encapsulation by making strong encapsulation opt out rather than opt in.

Hi.

Think about it another way. New applications written today (using new features and following all best practices) will not require any add-opens flags at all (in production; testing is another matter), and some of them will have --enable-native-access. So new code has no "alarm fatigue". In 15 years, most applications will have been written only starting today. There’s more Java code that hasn’t yet been written than old Java code, and we need to balance the needs of both old and new code. We certainly can’t sacrifice the needs of new code in favour of the old because then there simply won’t be much new code. Supporting new needs requires the JDK to pick up its development pace, and doing that requires strong encapsulation by default.

Obviously, we also need to take care of old code, but that code will simply not be able to run on new releases now that the JDK is changing more quickly if it’s relying on JDK internals (and we saw what happened when the pace picked up and strong encapsulation by default wasn’t there in the 8 -> 9+ migration). Such code will break with the alarms or without them. But having them makes sure that, as you correctly point out, the movement is in the right direction and always away from reaching into internals.

Just to be clear, an application with numerous --add-opens flags (for JDK internals) is an application that is likely to break soon with a new JDK update. It’s not the alarms that should bother you, but the understanding that they’re not false alarms. The more of these you have, the likelier it is that the program will break sooner. But --enable-native-access is different. The good news is that there are actions that codebases can and must do (if they want to continue working) to fix the real cause of the alarms.

> 
> I see the long-term wisdom of this, but I also find it a little grating considering that JNI has done a lot to pick up the slack in making many features available to Java developers: Unix domain sockets (pre-JDK16), fast AES-GCM (pre-JDK9), and Intel SHA Extensions (pre-JDK9) come to mind right away. If JNI is going to be de facto deprecated, it's reasonable for Java developers to wonder how their needs will be met without it.
> 
> [1] https://en.wikipedia.org/wiki/Alarm_fatigue
> [2] https://web.archive.org/web/20080719165816/http://news.cnet.com/Microsoft-Vista-feature-designed-to-annoy-users/2100-1016_3-6237191.html
> 

First of all, JNI is not being de facto deprecated. Its brand new, shiny, and quite beautiful alternative — FFM — is being restricted in precisely the same way (I hope you don’t think FFM, which we’ve invested so much in, is also being de facto deprecated). So the needs of JNI users will continue being met by JNI and, better yet, by FFM, which is superior to JNI in practically every way.

Second, let me do something unfair and redirect your words from something that’s not being de fact deprecated (JNI) to something that is: access to JDK internals. So let me pretend (and that’s unfair because maybe you didn’t mean that) that you said that reaching into JDK internals is what allowed libraries to offer functionality on JDK 6,7,8 that wouldn’t have been possible without that and it’s grating that now that capability is being restricted. But what other choice is there? Those actions were necessary because the JDK was slow to change, but the slow change of the JDK was also the only thing that kept those implementations working. When the pace of change picked up, many of them broke!

We simply cannot evolve the JDK at a satisfactory pace while at the same time treat every class and method as a stable API. We simply cannot implement deep functionality in Java rather than C++ if we have to consider the implications of any library saying, nah, I’m going to change the way that works. The choice is between evolving the JDK and not, and we chose to evolve it. Change brings some inconvenience but it’s not an indictment of the past. The past has brought us where we are today, and to keep going forward we must change — and in a rather measured way — the way we do things. The old ways worked right up until the point they stopped working, and that meant that some things had to change a little.

Applications and libraries now must stop relying on JDK internals (though not JNI!) if they want to continue working in the long run, and that’s inconvenient but still not nearly as inconvenient as the changes made by other languages/platforms. We try to only inconvenience some users when there’s no other choice, and even then we try really hard to keep that inconvenience to a minimum. Obviously, code maintainers would rather they not be inconvenienced at all, but consider that the alternative — stopping or considerably slowing down the platform’s evolution — would, in the long run, inconvenience them so much more.

So I would ask anyone who complains about the inconvenience caused to them — which is absolutely real! — to also consider how else we could do what we must do: be able to change internals without fear of breaking unsuspecting applications, offer security to those who want it, and be able to make promises about how Java code in the JDK behaves.

— Ron



More information about the jdk-dev mailing list