1

我有一个@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);
    }
}

坚持@Entity一个MyWrapper字段工作正常。但是当我执行查询以从数据库加载实体时,我得到一个NullPointerException. 堆栈跟踪和一些调试显示 EclipselinkMyWrapper通过调用其默认构造函数创建一个新实例,然后调用该setJPARepresentation()方法(如预期的那样)。

但是现在意外发生了:堆栈跟踪显示getJPARepresentation()从 setter 内部调用了,这当然会导致执行NullPointerException时返回wrappedField.toString()

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

事实是,代码中显然没有对 getter 的调用,并且堆栈跟踪显示没有行号指示从 setter 中调用 getter 的位置。所以我的结论是,Eclipselink 的字节码编织器生成了对 getter 的调用。

构建解决方法很容易,但我的问题是:为什么 Eclipselink 会这样做?

PS:我在 GlassFish Server Open Source Edition 3.1.2(build 23)中使用 EclipseLink 2.3.2.v20111125-r10461

4

1 回答 1

0

启用编织时(Glassfish 上的默认设置),EclipseLink 会将代码编织到属性获取/设置方法中,

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

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

现在这仍然很奇怪,因为您正在构建一个新对象,我不希望设置更改侦听器,因此希望绕过更改跟踪检查。您可以反编译代码以准确查看生成的内容。

最简单的解决方法是在您的 get 方法中进行空检查,这通常对您的代码来说可能是最好的。您还可以切换到字段访问,这不会在 get/set 方法中产生副作用。您还可以使用 Converter 来处理转换,而不是在 get/set 方法中进行转换。

于 2013-04-18T13:33:27.683 回答