JPA EclipseLink Weaver 在其 setter 中生成对 porperty getter 的调用 -> NullPointerException



我有一个@Embeddable类,它使用属性访问来包装JPA无法通过字段访问直接映射的另一个对象。它看起来像这样:

@Embeddable
@Access(AccessType.PROPERTY)
public class MyWrapper {
    @NotNull
    @Transient
    private WrappedType wrappedField;
    protected MyWrapper() {
    }
    public MyWrapper(WrappedType wrappedField) {
        this.wrappedField = wrappedField;
    }
    @Transient
    public WrappedType getWrappedField() {
        return wrappedField;
    }
    public void setWrappedField(WrappedType wrappedField) {
        this.wrappedField = wrappedField;
    }
    @Column(name = "wrappedTypeColumn")
    protected String getJPARepresentation() {
        return wrappedField.toString();
    }
    protected void setJPARepresentation(String jpaRepresentation) {
        wrappedField = new WrappedType(jpaRepresentation);
    }
}

使用MyWrapper字段持久化@Entity效果良好。但是,当我执行查询以从数据库加载实体时,我会得到一个NullPointerException。stacktrace和一些调试表明,Eclipselink通过调用其默认构造函数来创建MyWrapper的新实例,然后调用setJPARepresentation()方法(如预期(。

但现在意想不到的事情发生了:stacktrace显示getJPARepresentation()是从setter内部调用的,当执行返回wrappedField.toString()时,这当然会导致NullPointerException

java.lang.NullPointerException
    at MyWrapper.getJPARepresentation(MyWrapper.java:27)
    at MyWrapper.setJPARepresentation(MyWrapper.java)
    ... 109 more

事实是,代码中显然没有对getter的调用,stacktrace也没有显示行号,指示setter从哪里调用getter。因此,我的结论是,Eclipselink的字节码编织器生成了对getter的调用。

建立一个变通方法很容易,但我的问题是:为什么Eclipselink会这样做

p.S:我在GlassFish服务器开源版3.1.2(build 23(中使用EclipseLink 2.3.2.v20111125-r10461

启用编织时(Glassfish上的默认值(,EclipseLink将把代码编织到属性get/set方法中,用于

  • 变更跟踪
  • 获取组(部分对象(
  • 懒惰(关系(

对于更改跟踪支持,set方法将被编织以检查新值是否与旧值不同,因此它必须调用get方法来获取旧值。

现在这仍然很奇怪,因为由于您正在构建一个新对象,我不希望设置更改侦听器,所以希望绕过更改跟踪检查。你可以对代码进行反编译,看看到底生成了什么。

最简单的修复方法是在get方法中放入一个null检查,这可能对代码来说是最好的。您也可以切换到字段访问,这样在获取/设置方法中不会产生副作用。您也可以使用Converter来处理转换,而不是在get/set方法中进行转换。

相关内容

  • 没有找到相关文章

最新更新