我有一些JPA注释字段声明为final,如下所示:
@Column(name = "SOME_FIELD", updatable = false, nullable = false)
private final String someField;当实体插入数据库时,这些字段存储在数据库中。它们不能进一步更新。对于Java编程语言,这样的字段可以被认为是最终的。
使用EclipseLink静态编织插件,可以延迟加载实体,这是由于一些字节码检测。
我不知道JPA中是否正式允许这样的构造(最终字段),但我喜欢使用它们,因为它们在编译时强制执行这些字段不是要更新的。
在Java 8中,使用这些构造构建的程序运行良好。但是在Java9中,当涉及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> 这样的错误似乎是由于以下JVM规范所致:
否则,如果字段是最终字段,则必须在当前类中声明该字段,并且该指令必须在当前类的实例初始化方法()中进行。否则,将引发IllegalAccessError。
因此,我觉得有些编织工具需要一些更新来满足这个JVM规范。EclipseLink静态编织工具似乎就是其中之一。
问题
编辑
根据JPA规范,JPA中不允许最后字段:
实体类不能是最终的。实体类的任何方法或持久实例变量都不可能是最终的。
发布于 2017-12-12 11:30:41
请阅读JPA规范- 2-mrel-/index.html -第2.1节实体类:
实体类不能是最终的。实体类的任何方法或持久实例变量都不可能是最终的.
方法_persistence_set是通过编织(实体类的字节码操作)添加的代码,用于在默认构造函数(没有属性)创建类后初始化实体属性的值。Java 1.8甚至允许使用最后的字段,但Java 9不允许这样做。
现在您应该遵循JPA规范,而不应该将最终的持久性属性放入实体中。
发布于 2017-09-23 05:16:20
是最后的字段结构,如JPA?中所允许的。
正如发布说明中提到的那样,JDK-8157181也进行了一些更改,以限制编译器接受初始化方法之外的最终字段的修改。
根据Java规范,只允许putstatic字节码修改final字段
putstatic指令出现在当前类的class或interface初始化器方法<clinit>中。否则,必须抛出一个IllegalAccessError。
类似地,只允许putfield字节码修改final字段。
否则,必须抛出一个IllegalAccesError。
不满足条件(2)的方法违反了编译器的假设。并对其进行了检查,以便使用Java 9实现所需的条件。
您可以通过相同的BugReport来获得详细的解释。
,除了类的实例初始化方法()(作为临时解决方案)之外,还有JDK 9选项来禁用对最终字段分配的检查吗?
在JDK 9发行版中,Java完全执行了前面提到的限制,但仅针对具有HotSpot版本号为>= 53(Java9)的类文件。对于版本号< 53的类文件,仅部分强制执行限制(就像JDK 9之前的版本所做的那样)。也就是说,对于版本号< 53的类文件,可以在声明字段的类的任何方法中修改
final字段(不仅仅是类/实例初始化器)。
因此,您可以尝试用源代码和目标1.8编译您的代码,以检查这是否解决了目前的问题。使用最新的--release 8选项应该可以做到这一点。
发布于 2018-04-04 22:32:30
Eclipselink不承认这一点,但是,我希望在我的项目中这样做。所以我做了一个肮脏的“黑客”才能做到。基本上,我重写了eclipselink类org.eclipse.persistence.internal.jpa.weaving.ClassWeaver,并添加了以下方法:
@Override
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
if (cv != null) {
int newAccess = access;
if (!Modifier.isStatic(access) && Modifier.isFinal(access)) {
newAccess = access & (~Opcodes.ACC_FINAL);
}
return cv.visitField(newAccess, name, descriptor, signature, value);
}
return null;
}它将在织入时从实体上的非静态字段中移除所有最终修饰符。
我认为eclipselink应该考虑添加这个选项,至少作为一个选项。
https://stackoverflow.com/questions/46376045
复制相似问题