2011-01-13 4 views
2

우리는 Hibernate를 사용하는 웹 애플리케이션을 가지고있다. 코드베이스를 3.3.2에서 Hibernate 3.6으로 업그레이드 한 후, Hibernate에 의해 생성 된 프록시 데이터 객체는 일부 메소드에 대해서만 올바른 값을 리턴한다는 것을 발견했다. 그것은 구체적인 데이터 모델 클래스의 메서드는 잘 작동하지만, @MappedSuperclass 추상 슈퍼 클래스의 메소드가 작동하지 않는 것 같습니다. 여기 슈퍼 클래스 메소드에 대해 Hibernate 프록시 객체가 작동하지 않는다.

는 우리가 가지고있는 데이터 모델 :

@MappedSuperclass 
public abstract class DataObject implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "ID", unique = true, columnDefinition = "serial") 
    private int id; 

    // getter, setter, equals, hashcode implementations here 
} 

@MappedSuperclass 
public abstract class SecuredDataObject extends DataObject { 

    @Version 
    @Column(name = "Version") 
    private int version; 

    @Basic 
    @Column(name = "SecurityId", nullable = true) 
    private Integer securityId; 

    // getters, setters here 
} 

@MappedSuperclass 
public abstract class AuditedDataObject extends SecuredDataObject { 

    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "CreatedDate", nullable = true) 
    private Date createdDate; 

    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "LastUpdateDate", nullable = true) 
    private Date lastUpdateDate; 

    // getters, setters here 
} 

@Entity 
@Table(name = "Form") 
public class Form extends AuditedDataObject { 

    @Basic 
    @Column(name = "Name", length = 200, nullable = false) 
    private String name; 

    @Basic 
    @Column(name = "Path", length = 80, nullable = true) 
    private String path; 

    // getters, setters, other properties and methods here 

} 

이 최대 절전 모드 3.3.2에서 확인을 근무하지만, 업그레이드 후 3.6 응용 프로그램이 틀려서 간 최대 절전 모드로.

int formId = 1234; 
    Form form = (Form) sessionFactory.getCurrentSession().load(Form.class, formId); 

    System.out.print("id = "); 
    System.out.println(formId); 
    System.out.print("getId() = "); 
    System.out.println(form.getId()); 
    System.out.print("getSecurityId() = "); 
    System.out.println(form.getSecurityId()); 
    System.out.print("getVersion() = "); 
    System.out.println(form.getVersion()); 
    System.out.print("getLastUpdateDate() = "); 
    System.out.println(form.getLastUpdateDate()); 
    System.out.print("getCreatedDate() = "); 
    System.out.println(form.getCreatedDate()); 
    System.out.print("getName() = "); 
    System.out.println(form.getName()); 
    System.out.print("getPath() = "); 
    System.out.println(form.getPath()); 

그 코드의 출력은 : 이러한 방법

id = 1234 
getId() = 0 
getSecurityId() = 182 
getVersion() = 0 
getLastUpdateDate() = null 
getCreatedDate() = null 
getName() = Form name here 
getPath() = /path/here 

개의 잘못된 결과를 반환 한 다음 테스트 코드 문제 도시 getId() getVersion() getLastUpdateDate를() 및 getCreatedDate()가 0 또는 null을 반환했습니다. 데이터베이스의 실제 행에는 0이 아니거나 0이 아닌 값이 있습니다. 그러나 getName(), getPath() 및 가장 흥미롭게도 getSecurityId()가 정상적으로 작동했습니다.

왜 이런 일이 일어 났는지 설명 할 수 있습니까? 맵핑 된 수퍼 클래스와 관련된 근본적인 문제점입니까 아니면 이것이 발생할 수있는 또 다른 이유가 있습니까?

참고 Hibernate에 의해 반환 된 Form 객체가와 Javassist 프록시가되어 - 그것은 일반적으로 Form_$$_javassist_15 같은 클래스 이름 등


업데이트 한 디버거에서 볼 경우 :

이 문제에 보인다 Javassist가 아닌 Hibernate에서 발생하고있다. 나는 hibernate.properties에서 hibernate.bytecode.provider=cglib을 설정함으로써 바이트 코드 생성을 CGLIB로 바꿨지 만 CGLIB와 정확히 동일한 오류 결과를 얻는다. (그리고 Hibernate에 의해 반환 된 클래스 이름이 Form$$EnhancerByCGLIB$$4f3b4523이되기 때문에 확인 된 CGLIB가 작동 중이다.)

아직 잘못되었다는 것을 확인하는 데는 더 이상 거리가 멀습니다.

+0

아마도 버그 보고서를 제출해야합니다.이 예기치 않은 동작을 증명하는 테스트가 있고이 테스트를 최대 절전 모드로만 분리 한 경우에는 버그 보고서를 작성하는 것이 좋습니다. 대개 Hibernate 팀은 "테스트를 제공하여 증명하십시오"라고 대답합니다 :) – chris

+0

일부 getter 및 setter가 'final'이기 때문에 나는 내 잘못이었습니다. 그러나 나는 Hibernate 문서에서 이것을 수행하는 것에 대한 경고를 찾을 수 없기 때문에 문서화 문제를보고 할 수도있다. 문서는 최종 클래스에 대해서는 경고하지만 최종 메소드에 대해서는 경고하지 않습니다 ... – gutch

답변

3

대답을 찾았습니다. 수퍼 클래스의 getter와 setter 중 일부가 final으로 표시되었습니다.

뒤늦은 견해로는이 방법이 최종적 이었기 때문에 프록시 클래스가이를 무시할 수 없었습니다. 그래서 해결책은 맵핑 된 수퍼 클래스의 getter와 setter에서 final을 제거하는 것입니다. - getSecurityId() 아니었다 반면 getVersion()final이었다 내 테스트가 제대로 securityId을 반환했지만 제대로 version을 반환하지 않은 이유

@MappedSuperclass 
public abstract class SecuredDataObject extends DataObject { 

    @Version 
    @Column(name = "Version") 
    private int version; 

    @Basic 
    @Column(name = "SecurityId", nullable = true) 
    private Integer securityId; 

    // Note - method IS NOT final 
    public Integer getSecurityId() { 
     return securityId; 
    } 

    public void setSecurityId(Integer securityId) { 
     this.securityId = securityId; 
    } 

    // Note - method IS final 
    public final int getVersion() { 
     return version; 
    } 

    public final void setVersion(final int version) { 
     this.version = version; 
    } 
} 

그것은 설명 : 여기에

SecuredDataObject에 정의 된 getter 및 setter입니다.

요약하면 getter와 setters를 최대 절전 모드로 프록시하려고 시도 할 경우 final으로 표시하지 마십시오!

관련 문제