I have some JPA annotated fields declared final like this:
@Column(name = "SOME_FIELD", updatable = false, nullable = false)
private final String someField;
Those fields are stored in the database when the entity is inserted in the database. They cannot further be updated. For the Java programming language, such fields can be considered final.
With the EclipseLink static weaving plugin, it's possible to lazy load entities, owing to some byte code instrumentation.
I don't know if such constructs (final fields) are officially allowed in JPA, but I like to use them, since they enforce at compile time that these fields are not meant to be updated.
In Java 8, programs built with such constructs run fine. But in Java 9, when the EclipseLink static weaving is involved, I get the following runtime exception:
Caused by: java.lang.IllegalAccessError: Update to non-static final field xxx.yyy.SomeEntity.someField attempted from a different method (_persistence_set) than the initializer method <init>
Such an error seems to be due to the following JVM specification:
Otherwise, if the field is final, it must be declared in the current class, and the instruction must occur in an instance initialization method () of the current class. Otherwise, an IllegalAccessError is thrown.
Therefore, I feel like some weaving tools need some update to fulfill this JVM specification. The EclipseLink static weaving tool seems to be one of them.
Questions:
Edit:
Final fields are not allowed in JPA, as per JPA specifications:
The entity class must not be final. No methods or persistent instance variables of the entity class may be final.
Are final field constructs such as those presented here allowed in JPA?
As mentioned in the release note JDK-8157181 as well there is a change brought to restrict Compilers to accept modification of final fields outside initializer methods.
According to the Java VM Specification, the putstatic
bytecode is allowed to modify a final
field only
putstatic
instruction appears in the class
or interface
initializer method <clinit>
of the current class.Otherwise, an IllegalAccessError
must be thrown.
Similarly, the putfield
bytecode is allowed to modify a final
field only
Otherwise, an IllegalAccesError
must be thrown.
Methods that do not satisfy condition (2) violate the assumptions of the compilers. and have been kept under a check to implement the desired condition with Java 9.
You can follow the BugReport over the same for a detailed explanation.
Is there a JDK 9 option to disable the check for final field assignment elsewhere than only in the instance initialization method() of the class (as a temporary workaround)?
With the JDK 9 release, the HotSpot VM fully enforces the previously mentioned restrictions, but only for class files with version number >= 53(Java 9). For class files with version numbers < 53, restrictions are only partially enforced (as it is done by releases preceding JDK 9). That is, for class files with version number < 53
final
fields can be modified in any method of the class declaring the field (not only class/instance initializers).
So, you can try compiling your code with source and target 1.8 to check if that resolves the issue for now. This should be doable with --release 8
option using the latest javac
tool.
Please read JPA specification - http://download.oracle.com/otndocs/jcp/persistence-2_2-mrel-eval-spec/index.html - Section 2.1 The Entity Class:
The entity class must not be final. No methods or persistent instance variables of the entity class may be final.
Method _persistence_set is code added by weaving (bytecode manipulation of entity classes) and is used to initialize values of entity attributes after class was created by default constructor (with no attributes) call. Java 1.8 allowed this even with final fields, but Java 9 does not.
You should now follow JPA specification and should not put final persistence attributes into your entities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With