首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Java 9上带有最终字段的eclipselink静态编织

在Java 9上带有最终字段的eclipselink静态编织
EN

Stack Overflow用户
提问于 2017-09-23 04:27:53
回答 3查看 1.6K关注 0票数 5

我有一些JPA注释字段声明为final,如下所示:

代码语言:javascript
复制
@Column(name = "SOME_FIELD", updatable = false, nullable = false)
private final String someField;

当实体插入数据库时,这些字段存储在数据库中。它们不能进一步更新。对于Java编程语言,这样的字段可以被认为是最终的。

使用EclipseLink静态编织插件,可以延迟加载实体,这是由于一些字节码检测。

我不知道JPA中是否正式允许这样的构造(最终字段),但我喜欢使用它们,因为它们在编译时强制执行这些字段不是要更新的。

在Java 8中,使用这些构造构建的程序运行良好。但是在Java9中,当涉及EclipseLink静态编织时,我得到以下运行时异常:

代码语言:javascript
复制
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中是否允许像这里这样的最后字段构造?
  • 除了类的实例初始化方法()(作为临时解决方案)之外,是否还有JDK 9选项来禁用对最终字段赋值的检查?

编辑

根据JPA规范,JPA中不允许最后字段:

实体类不能是最终的。实体类的任何方法或持久实例变量都不可能是最终的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-12-12 11:30:41

请阅读JPA规范- 2-mrel-/index.html -第2.1节实体类:

实体类不能是最终的。实体类的任何方法或持久实例变量都不可能是最终的.

方法_persistence_set是通过编织(实体类的字节码操作)添加的代码,用于在默认构造函数(没有属性)创建类后初始化实体属性的值。Java 1.8甚至允许使用最后的字段,但Java 9不允许这样做。

现在您应该遵循JPA规范,而不应该将最终的持久性属性放入实体中。

票数 1
EN

Stack Overflow用户

发布于 2017-09-23 05:16:20

是最后的字段结构,如JPA?中所允许的。

正如发布说明中提到的那样,JDK-8157181也进行了一些更改,以限制编译器接受初始化方法之外的最终字段的修改。

根据Java规范,只允许putstatic字节码修改final字段

  1. 如果字段是在当前类(声明当前方法的类)中声明的,则
  2. 如果putstatic指令出现在当前类的classinterface初始化器方法<clinit>中。

否则,必须抛出一个IllegalAccessError

类似地,只允许putfield字节码修改final字段。

  1. 如果字段是在当前类中声明的,则
  2. 如果指令出现在当前类的实例初始化器方法中。

否则,必须抛出一个IllegalAccesError

不满足条件(2)的方法违反了编译器的假设。并对其进行了检查,以便使用Java 9实现所需的条件。

您可以通过相同的BugReport来获得详细的解释。

,除了类的实例初始化方法()(作为临时解决方案)之外,还有JDK 9选项来禁用对最终字段分配的检查吗?

在JDK 9发行版中,Java完全执行了前面提到的限制,但仅针对具有HotSpot版本号为>= 53(Java9)的类文件。对于版本号< 53的类文件,仅部分强制执行限制(就像JDK 9之前的版本所做的那样)。也就是说,对于版本号< 53的类文件,可以在声明字段的类的任何方法中修改final字段(不仅仅是类/实例初始化器)。

因此,您可以尝试用源代码和目标1.8编译您的代码,以检查这是否解决了目前的问题。使用最新的--release 8选项应该可以做到这一点。

票数 4
EN

Stack Overflow用户

发布于 2018-04-04 22:32:30

Eclipselink不承认这一点,但是,我希望在我的项目中这样做。所以我做了一个肮脏的“黑客”才能做到。基本上,我重写了eclipselink类org.eclipse.persistence.internal.jpa.weaving.ClassWeaver,并添加了以下方法:

代码语言:javascript
复制
        @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应该考虑添加这个选项,至少作为一个选项。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46376045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档