Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Hibernate代理存在的情况下,我需要在哪里避免直接访问字段?_Java_Hibernate_Jpa_Proxy - Fatal编程技术网

Java 在Hibernate代理存在的情况下,我需要在哪里避免直接访问字段?

Java 在Hibernate代理存在的情况下,我需要在哪里避免直接访问字段?,java,hibernate,jpa,proxy,Java,Hibernate,Jpa,Proxy,我有一个简单的实体类,如下所示: @Entity public class Foo { @NotNull @Column private String name; public String getName() { return this.name; } public void setName(String name) { this.name = name; } } 现在面对Hibernate代理,我知道我不能依赖getClass()返回Foo.class,在实体

我有一个简单的实体类,如下所示:

@Entity public class Foo {

    @NotNull @Column private String name;

    public String getName() { return this.name; }

    public void setName(String name) { this.name = name; }
}
现在面对Hibernate代理,我知道我不能依赖
getClass()
返回
Foo.class
,在实体层次结构中我也不能依赖
instanceof
。我知道我不应该在
equals
方法中直接访问
other.name
。例如,我不应该这样做:

// in class Foo:
@Override public boolean equals(Object obj) {

    // instanceof is fine in this case since Foo has no entity superclass
    if (!(obj instanceof Foo)) {
        return false;
    }
    Foo other = (Foo) obj;

    // hold up! if other is a proxy, then other.name will be null
    return Objects.equal(name, other.name);
}
我的问题是,访问
other.name
的确切位置是否不安全?访问
此.name
是否有任何不安全之处


这很快就要投入生产了,我在这里没有“试一试”的奢侈方式。

为了回答这个问题,我启动了我的
Foo
类来报告不同上下文中的字段访问。我补充说:

public String callGetNamePublic() {
    System.out.print("callGetNamePublic: ");
    return getNamePublic();
}

public String getNamePublic() {
    System.out.println("getNamePublic: " + name);
    return name;
}

public String callGetNameProtected() {
    System.out.print("callGetNameProtected: ");
    return getNameProtected();
}

protected String getNameProtected() {
    System.out.println("getNameProtected: " + name);
    return name;
}

public String callGetNamePackage() {
    System.out.print("callGetNamePackage: ");
    return getNamePackage();
}

String getNamePackage() {
    System.out.println("getNamePackage: " + name);
    return name;
}

public String callGetNamePrivate() {
    System.out.print("callGetNamePrivate: ");
    return getNamePrivate();
}

private String getNamePrivate() {
    System.out.println("getNamePrivate: " + name);
    return name;
}

public static class FooSubclass extends Foo {

    public String callOtherGetNamePublic(Foo other) {
        System.out.print("callOtherGetNamePublic: ");
        return other.getNamePublic();
    }

    public String callOtherGetNameProtected(Foo other) {
        System.out.print("callOtherGetNameProtected: ");
        return other.getNameProtected();
    }

    public String callOtherGetNamePackage(Foo other) {
        System.out.print("callOtherGetNamePackage: ");
        return other.getNamePackage();
    }

    public String callOtherGetNamePrivate(Foo other) {
        System.out.print("callOtherGetNamePrivate: ");
        return other.getNamePrivate();
    }

    public String accessOtherName(Foo other) {
        System.out.print("accessOtherName: " + other.name);
        return other.name;
    }
}
然后我装配了一个测试来拉一个
Foo
代理对象,并调用这些方法。像这样:

// I'll leave this to your imagination ;)
Foo foo1 = getFooProxy();

foo1.getName();
foo1.getNamePublic();
foo1.callGetNamePublic();
foo1.callGetNameProtected();
foo1.callGetNamePackage();
foo1.callGetNamePrivate();

FooSubclass foo2 = new Foo.FooSubclass();
foo2.callOtherGetNamePublic(foo1);
foo2.callOtherGetNameProtected(foo1);
foo2.callOtherGetNamePackage(foo1);
foo2.callOtherGetNamePrivate(foo1);
foo2.accessOtherName(foo1);
结果如下:

getNamePublic: testName
callGetNamePublic: getNamePublic: testName
callGetNameProtected: getNameProtected: testName
callGetNamePackage: getNamePackage: testName
callGetNamePrivate: getNamePrivate: testName
callOtherGetNamePublic: getNamePublic: testName
callOtherGetNameProtected: getNameProtected: testName
callOtherGetNamePackage: getNamePackage: testName
callOtherGetNamePrivate: getNamePrivate: null
accessOtherName: null
我发现在任何最终方法中都需要避免直接访问字段。如果将以下任何方法更改为final,则相应的结果将从
testName
更改为
null

  • getNamePublic
  • getNameProtected
  • getNamePackage
  • getNamePrivate

因此答案是:面对Hibernate代理,直接字段访问的唯一限制是:(1)直接字段访问
其他.name
,(2)对
其他
上的私有方法的内部调用,以及(3)在任何最终方法内部。

John,如果您使用IntelliJ IDEA,并且您仍然感兴趣,我做了一个插件来检查: