Frage

Wir haben eine Webanwendung, die Hibernate verwendet.Nach dem Upgrade der Codebasis auf Hibernate 3.6 (von 3.3.2) habe ich festgestellt, dass die von Hibernate generierten Proxy-Datenobjekte nur für einige Methoden den richtigen Wert zurückgeben.Es scheint, dass Methoden in einer konkreten Datenmodellklasse gut funktionieren, aber Methoden in @MappedSuperclass Abstrakte Superklassen funktionieren nicht.

Hier ist das Datenmodell, das wir haben:

@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

}

Dies funktionierte in Hibernate 3.3.2 einwandfrei, aber nach dem Upgrade auf Hibernate 3.6 ist die Anwendung schief gelaufen.Der 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());

Die Ausgabe dieses Codes ist:

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

Vier dieser Methoden haben falsche Ergebnisse zurückgegeben:getId(), getVersion(), getLastUpdateDate() und getCreatedDate() haben 0 oder null zurückgegeben.Die tatsächliche Zeile in der Datenbank enthält Werte ungleich Null/Nicht-Null.Allerdings haben getName(), getPath() und vor allem getSecurityId() einwandfrei funktioniert.

Kann jemand erklären, warum das passiert?Handelt es sich um ein grundlegendes Problem bei zugeordneten Superklassen oder gibt es einen anderen Grund, warum dies auftreten könnte?

Notiere dass der Form Das von Hibernate zurückgegebene Objekt ist ein Javassist-Proxy. Wenn es in einem Debugger angezeigt wird, hat es normalerweise einen Klassennamen wie Form_$$_javassist_15 usw.


Aktualisieren:

Dieses Problem scheint im Ruhezustand aufzutreten, nicht in Javassist.Ich habe die Bytecode-Generierung per Einstellung auf CGLIB umgestellt hibernate.bytecode.provider=cglib in hibernate.properties, erhalten aber genau die gleichen fehlerhaften Ergebnisse, wenn CGLIB vorhanden ist (und bestätigt wird, dass CGLIB funktioniert, da der von Hibernate zurückgegebene Klassenname lautet). Form$$EnhancerByCGLIB$$4f3b4523).

Allerdings bin ich immer noch nicht näher dran, herauszufinden, warum es schiefgeht.

War es hilfreich?

Lösung

Ich habe die Antwort gefunden:Einige der Getter und Setter der Superklassen waren markiert final.

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

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

@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 mein Test zurückkam securityId richtig, kam aber nicht zurück version richtig – getVersion() War final wohingegen getSecurityId() war nicht.

Zusammenfassend lässt sich sagen, dass Sie Ihre Getter und Setter nicht als markieren final wenn Hibernate versuchen könnte, sie zu vertreten!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top