我有一个简单的实体类如下:
@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
。我知道我不应该直接使用other.name
方法访问equals
。例如,我不应该这样做:
// 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
是不安全的?访问this.name
是不安全的?
这很快就会投入生产,我在这里没有“试一试”的奢侈品。
答案 0 :(得分:0)
为了回答这个问题,我想起了我的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
我发现您需要避免在任何最终方法中直接访问字段。如果您将以下任何方法更改为最终,相应的结果将从testName
更改为null
:
getNamePublic
getNameProtected
getNamePackage
getNamePrivate
所以答案是:面对Hibernate代理的直接字段访问的唯一限制是(1)对other.name
的直接字段访问,(2)other
内私有方法的调用, (3)在任何最终方法中。