2011-01-13 4 views
2

Wir haben eine Webanwendung, die Hibernate verwendet. Nach dem Upgrade der Codebase auf Hibernate 3.6 (ab 3.3.2) habe ich festgestellt, dass die von Hibernate generierten Proxy-Datenobjekte nur den korrekten Wert für einige Methoden zurückgeben. Es scheint, dass Methoden in einer konkreten Datenmodellklasse gut funktionieren, aber Methoden in @MappedSuperclass abstrakten Oberklassen funktionieren nicht. HierHibernate-Proxy-Objekt funktioniert nicht für Superklassenmethoden

ist das Datenmodell haben wir:

@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 

} 

Das funktionierte OK in Hibernate 3.3.2, aber nach dem Upgrade 3.6 die Anwendung Hibernate hat schief gegangen. Das folgende Testcode veranschaulicht das Problem:

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()); 

Der Ausgang dieses Codes ist:

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

Vier dieser Verfahren haben eine falsche Ergebnisse zurückgegeben: getId(), getVersion(), getLastUpdateDate() und getCreatedDate() hat 0 oder null zurückgegeben. Die tatsächliche Zeile in der Datenbank hat Werte ungleich null/ungleich null. GetName(), getPath() und am seltsamsten getSecurityId() haben jedoch gut funktioniert.

Kann jemand erklären, warum das passiert? Ist es ein grundlegendes Problem mit abgebildeten Superklassen oder gibt es einen anderen Grund, warum dies passieren könnte?

Beachten Sie, dass die Form Objekt zurückgegeben von Hibernate ist ein Javassist Proxy - wenn in einem Debugger betrachtet es hat in der Regel ein Klassenname wie Form_$$_javassist_15 usw.


Update:

Dieses Problem scheint in Hibernate auftreten, nicht in Java. Ich habe die Bytecode-Generierung auf CGLIB umgestellt, indem ich in hibernate.properties gesetzt habe, aber exakt die gleichen fehlerhaften Ergebnisse mit CGLIB an der richtigen Stelle erhalten habe (und bestätigt, dass CGLIB funktioniert, weil der von Hibernate zurückgegebene Klassenname Form$$EnhancerByCGLIB$$4f3b4523 wird).

Ich bin immer noch nicht näher zu identifizieren, warum es falsch läuft, obwohl.

+0

Vielleicht müssen Sie einen Fehlerbericht ablegen.Wenn Sie einen Test haben, der dieses unerwartete Verhalten beweist, und Sie den Test nur auf Hibernate isoliert haben, ist dies ein guter Kandidat für einen Fehlerbericht. Normalerweise wird das Hibernate-Team Sie herausfordern "Beweisen Sie es, indem Sie einen Test zur Verfügung stellen" :) – chris

+0

Ich war meine Schuld, weil einige Getter und Setter "endgültig" waren. Ich konnte jedoch in der Hibernate-Dokumentation keine Warnung finden, weshalb ich ein Dokumentationsproblem melden könnte. Die Dokumentation warnt vor endgültigen Klassen, aber nicht nach finalen Methoden ... – gutch

Antwort

3

Ich fand die Antwort: einige der Getter und Setter auf den Oberklassen wurden markiert final.

Im Nachhinein ist dies offensichtlich ... weil die Methoden endgültig waren, konnten die Proxy-Klassen sie nicht überschreiben. Die Lösung besteht darin, final von allen Gettern und Setter in zugeordneten Superklassen zu entfernen.

Hier sind die Getter und Setter, die auf SecuredDataObject definiert wurden:

@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; 
    } 
} 

Es erklärt, warum wurde mein Test securityId richtig Rückkehr aber nicht version richtig Rückkehr - getVersion() war final während getSecurityId() nicht.

Also, zusammenfassend, markieren Sie nicht Ihre Getter und Setter als final, wenn Hibernate versuchen könnte, sie proxy!

Verwandte Themen