Domanda

Abbiamo un'applicazione web che utilizza Sospensione.Dopo l'aggiornamento il codice di base per la Sospensione 3.6 (da 3.3.2) ho scoperto che i dati del proxy oggetti generati da Sospensione solo restituisce il valore corretto per alcuni metodi.Sembra che i metodi di calcestruzzo classe del modello di dati funzionare bene, ma i metodi in @MappedSuperclass abstract superclassi non funzionano.

Qui è il modello di dati abbiamo:

@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

}

Questo ha funzionato bene in Sospensione 3.3.2, ma dopo l'aggiornamento a Sospensione 3.6 l'applicazione è andato storto.Il codice test riportato di seguito viene illustrato il problema:

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

L'output di tale codice è:

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

Quattro di questi metodi hanno restituito risultati non corretti:getId(), getVersion(), getLastUpdateDate() e getCreatedDate() ha restituito 0 o null.L'attuale riga nel database è non-zero / valori non nulli.Tuttavia getName(), getPath() e, più curiosamente getSecurityId() hanno lavorato bene.

Qualcuno può spiegare perché questo sta accadendo?È un problema fondamentale con il mappato superclassi, oppure c'è un altro motivo per cui questo potrebbe accadere?

Si noti che il Form oggetto restituito da Hibernate è un Javassist proxy, se vista in un debugger, in genere, un nome di classe come Form_$$_javassist_15 ecc.


Aggiornamento:

Questo problema sembra essere che si verificano in modalità di Ibernazione, non Javassist.Ho acceso il bytecode generazione di CGLIB impostando hibernate.bytecode.provider=cglib in modalità di ibernazione.proprietà, ma ottenere esattamente gli stessi risultati errati con CGLIB (e confermato CGLIB sta lavorando perché il nome della classe restituito dalla Sospensione diventa Form$$EnhancerByCGLIB$$4f3b4523).

Io sono ancora più vicini a identificare il motivo per cui è sbagliato, però.

È stato utile?

Soluzione

Ho trovato la risposta:alcuni dei metodi getter e setter sul superclassi sono stati contrassegnati final.

Col senno di poi, questo è ovvio...perché i metodi sono stati finale, le classi proxy non poteva ignorarle.Quindi la soluzione è rimuovere final da qualsiasi getter e setter in mappato superclassi.

Qui ci sono i getter e i setter sono stati definiti sulla 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;
    }
}

Ciò spiega perché il mio test era di ritorno securityId correttamente, ma non era di ritorno version correttamente — getVersion() era final considerando che getSecurityId() non era.

Quindi, in sintesi, non segnare il tuo getter e setter come final se la Sospensione potrebbe tentare di proxy loro!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top