JEP 539: Strict Field Initialization in the JVM moved to preview

29 pointsposted 2 hours ago
by za3faran

11 Comments

ashishb

43 minutes ago

Weirdly enough, I encountered this once while writing code.

You can trigger it with a single class that initializes one field with a call to a static method of the same class.

And a second static field that is initialized by performing a computation on the first static field.

Here's a simplified example of the same - https://ashishb.net/programming/java/final-variable-with-two...

cogman10

an hour ago

This is a great change that will undoubtedly cause a lot of headaches.

There's a number of libraries (particularly around serialization/marshaling) which will end up mutating `final` fields. In fact, this is a trick I've pulled once or twice in my own code for "reasons" (generally needing to modify behavior of a library because it was deficient).

I suspect this will be one of those things that ends up requiring java devs everywhere to bump up the versions of the libraries they use.

debugnik

8 minutes ago

That's a separate series of JEPs known as "final means final", also starting to land nowadays.

https://openjdk.org/jeps/500

cogman10

4 minutes ago

I believe these 2 are effectively linked.

There's a jdk.internal API which will work as an escape hatch, but that does come with the need for non-compliant libraries to switch over to it. That safety hatch also only allows the setting of final fields once before observation (which is generally fine). So if your code is doing something more esoteric that sets a final field multiple times you will be SOL.

In any case, if you are using the sun.misc.Unsafe methods for setting final and private fields you'll need to update.

kasperni

an hour ago

Strict Field Initialization is opt-in. A flag needs to be set in the classfile in order to enable it. So should not effect any existing code.

cogman10

an hour ago

It won't bite initially, it will bite when you go to update your version of javac in the future and this becomes the default. Or when you update a library that just so happened to be compiled with a newer version of javac.

This particularly matters when you have something likes this

    class Local {
       private final ThirdPartyObject tpo;
    }
or even something like this

    class Local {
      private final LocalDate ld;
    }

vips7L

25 minutes ago

Extremely easy to fix. Turn it into a record. I’m also pretty sure that cracking final fields is already disabled by default.

cogman10

8 minutes ago

> Extremely easy to fix.

Nope, if the deserializer is initializing that field by directly setting values both by the field and by the internals of the field, it'll be a problem. The fix is to update the deserializer to a newer version. Apache Fury recently fixed this very issue, but it still relies on internal JDK APIs in order to do it's work.

> I’m also pretty sure that cracking final fields is already disabled by default.

Nope. There's sun.misc.Unsafe apis that allow for cracking and modifying those final fields. There are new jdk.internal APIs for doing the same that you'd have to move over to in order to accomplish the same. This JEP is about making final (mostly) meaning final. At very least, it will enforce that final once observed is final with the internal APIs allowing a final field to be set once, just outside the constructor.

rvcdbn

43 minutes ago

oracle planning a new jvm language? have we ever seen a feature like this that is explicitly not usable from Java?

Skinney

25 minutes ago

This is required in order to implement value classes in Java (project valhala).