Sté*_*cel 5 jpa eclipselink compile-time-weaving java-9
我有一些JPA注释字段,如下所示:
@Column(name = "SOME_FIELD", updatable = false, nullable = false)
private final String someField;
Run Code Online (Sandbox Code Playgroud)
当实体插入数据库时,这些字段存储在数据库中.它们无法进一步更新.对于Java编程语言,可以将这些字段视为final.
使用EclipseLink静态编织插件,由于某些字节代码检测,可能会延迟加载实体.
我不知道JPA中是否正式允许这样的构造(最终字段),但我喜欢使用它们,因为它们在编译时强制执行这些字段并不是要更新.
在Java 8中,使用这种结构构建的程序运行良好.但是在Java 9中,当涉及EclipseLink静态编织时,我得到以下运行时异常:
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>
Run Code Online (Sandbox Code Playgroud)
这样的错误似乎是由于以下JVM规范:
否则,如果该字段是final,则必须在当前类中声明,并且该指令必须在当前类的实例初始化方法()中发生.否则,抛出IllegalAccessError.
因此,我觉得一些编织工具需要一些更新才能实现这个JVM规范.EclipseLink静态编织工具似乎就是其中之一.
问题:
编辑:
根据JPA规范,JPA中不允许使用最终字段:
实体类不能是最终的.实体类的方法或持久性实例变量可能不是最终的.
JPA 中是否允许使用此处介绍的最终字段构造?
正如发行说明JDK-8157181中提到的,还进行了一项更改,以限制编译器接受初始化程序方法之外的最终字段的修改。
根据Java VM规范,putstatic字节码只允许修改一个final字段
putstatic指令出现在当前类的class或interface初始化方法中。<clinit>否则,IllegalAccessError必须抛出一个。
同样,putfield字节码只允许修改一个final字段
否则,IllegalAccesError必须抛出一个。
不满足条件 (2) 的方法违反了编译器的假设。并一直在检查以使用 Java 9 实现所需的条件。
您可以关注BugReport以获得详细说明。
是否有 JDK 9 选项可以在类的实例初始化 method() 之外的其他地方禁用对最终字段分配的检查(作为临时解决方法)?
在 JDK 9 版本中,HotSpot VM 完全强制执行前面提到的限制,但仅适用于版本号 >= 53 (Java 9) 的类文件。对于版本号 < 53 的类文件,仅部分强制执行限制(正如 JDK 9 之前的版本所做的那样)。也就是说,对于版本号 < 53 的
final类文件,可以在声明该字段的类的任何方法中修改字段(不仅是类/实例初始值设定项)。
因此,您可以尝试使用源和目标 1.8 编译代码,以检查是否可以暂时解决问题。这应该可以通过--release 8使用最新javac工具的选项来实现。
小智 1
请阅读 JPA 规范 - http://download.oracle.com/otndocs/jcp/persistence-2_2-mrel-eval-spec/index.html - 第 2.1 节实体类:
实体类不能是最终的。实体类的任何方法或持久实例变量都不能是最终的。
方法 _persistence_set 是通过编织(实体类的字节码操作)添加的代码,用于在通过默认构造函数(无属性)调用创建类后初始化实体属性的值。Java 1.8 即使对于 Final 字段也允许这样做,但 Java 9 不允许。
您现在应该遵循 JPA 规范,并且不应将最终持久性属性放入实体中。