Hibernate n: m extractHashCode lança NullPointerException

Recebo a seguinte exceção ao inserir um objeto com hibernação. A leitura do banco de dados funciona como um encanto. Eu usoMySQL 5.5 como provedor de banco de dados ehibernate 3.6.5.

Tenho o seguinte esquema de banco de dados:

cell(id,cellid,lac,mcc,mnc,insertTime)
location(id,latitude,longitude,altitude,accuracy,heading,hdop,vdop,pdop,insertTime)
cellatlocation(servingCell,neighbourCell,location,signalStrength,insertTime)

where id na célula e local são as chaves primárias e servingCell, neighbourCell e location são a chave primária composta na localização da célul

java.lang.NullPointerException
at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode(AbstractTypeDescriptor.java:88)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:196)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:191)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:325)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:222)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
at org.hibernate.engine.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:286)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:211)
at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:103)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:673)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:345)
at $Proxy17.saveOrUpdate(Unknown Source)

As classes que quero inserir: Cell.java

@Entity
@Table(name = "cell", catalog = "crisis")
public class Cell implements Serializable {

private static final long serialVersionUID = -8532796958180260393L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Integer mnc;
private Integer mcc;
private Long cellid;
private Integer lac;
@org.hibernate.annotations.Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime insertTime;
@OneToMany(mappedBy = "pk.servingCell")
private List<CellAtLocation> cellAtLocation = new LinkedList<CellAtLocation>();

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Integer getMnc() {
    return mnc;
}

public void setMnc(Integer mnc) {
    this.mnc = mnc;
}

public Integer getMcc() {
    return mcc;
}

public void setMcc(Integer mcc) {
    this.mcc = mcc;
}

public Long getCellid() {
    return cellid;
}

public void setCellid(Long cellid) {
    this.cellid = cellid;
}

public Integer getLac() {
    return lac;
}

public void setLac(Integer lac) {
    this.lac = lac;
}

public DateTime getInsertTime() {
    return insertTime;
}

public void setInsertTime(DateTime insertTime) {
    this.insertTime = insertTime;
}

public List<CellAtLocation> getCellAtLocation() {
    return cellAtLocation;
}

public void setCellAtLocation(List<CellAtLocation> cellAtLocation) {
    this.cellAtLocation = cellAtLocation;
}
}

Location.java

@Entity
@Table(name = "location", catalog = "crisis")
public class Location implements Serializable {

private static final long serialVersionUID = 2197290868029835453L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Double latitude;
private Double longitude;
private Double altitude;
private Double accuracy;
private Double heading;
private Double hdop;
private Double vdop;
private Double pdop;
@org.hibernate.annotations.Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime insertTime;

@OneToMany(mappedBy = "pk.location")
private List<CellAtLocation> cellAtLocation = new LinkedList<CellAtLocation>();

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Double getLatitude() {
    return latitude;
}

public void setLatitude(Double latitude) {
    this.latitude = latitude;
}

public Double getLongitude() {
    return longitude;
}

public void setLongitude(Double longitude) {
    this.longitude = longitude;
}

public Double getAltitude() {
    return altitude;
}

public void setAltitude(Double altitude) {
    this.altitude = altitude;
}

public Double getAccuracy() {
    return accuracy;
}

public void setAccuracy(Double accuracy) {
    this.accuracy = accuracy;
}

public Double getHeading() {
    return heading;
}

public void setHeading(Double heading) {
    this.heading = heading;
}

public Double getHdop() {
    return hdop;
}

public void setHdop(Double hdop) {
    this.hdop = hdop;
}

public Double getVdop() {
    return vdop;
}

public void setVdop(Double vdop) {
    this.vdop = vdop;
}

public Double getPdop() {
    return pdop;
}

public void setPdop(Double pdop) {
    this.pdop = pdop;
}

public DateTime getInsertTime() {
    return insertTime;
}

public void setInsertTime(DateTime insertTime) {
    this.insertTime = insertTime;
}

public List<CellAtLocation> getCellAtLocation() {
    return cellAtLocation;
}

public void setCellAtLocation(List<CellAtLocation> cellAtLocation) {
    this.cellAtLocation = cellAtLocation;
}

}

CellAtLocation.java

@Entity
@Table(name = "cellatlocation", catalog = "crisis")
@AssociationOverrides({ @AssociationOverride(name = "pk.servingCell", joinColumns = @JoinColumn(name = "servingCell")),
    @AssociationOverride(name = "pk.neighbourCell", joinColumns = @JoinColumn(name = "neighbourCell")),
    @AssociationOverride(name = "pk.location", joinColumns = @JoinColumn(name = "location")) })

public class CellAtLocation implements Serializable {
private static final long serialVersionUID = -4440795783726362367L;
private CellAtLocationPk pk = new CellAtLocationPk();
private Integer signalStrength;

@EmbeddedId
private CellAtLocationPk getPk() {
    return pk;
}

@SuppressWarnings("unused")
private void setPk(CellAtLocationPk pk) {
    this.pk = pk;
}

@Transient
public Cell getServingCell() {
    return getPk().getServingCell();
}

public void setServingCell(Cell cell) {
    getPk().setServingCell(cell);
}

@Transient
public Cell getNeighbourCell() {
    return getPk().getNeighbourCell();
}

public void setNeighbourCell(Cell cell) {
    getPk().setNeighbourCell(cell);
}

@Transient
public Location getLocation() {
    return getPk().getLocation();
}

public void setLocation(Location location) {
    getPk().setLocation(location);
}

public Integer getSignalStrength() {
    return signalStrength;
}

public void setSignalStrength(Integer signalStrength) {
    this.signalStrength = signalStrength;
}

public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;
    CellAtLocation that = (CellAtLocation) o;
    if (getPk() != null ? !getPk().equals(that.getPk()) : that.getPk() != null)
        return false;
    return true;
}

public int hashCode() {
    return (getPk() != null ? getPk().hashCode() : 0);
}
}

e finalmente a chave primária mapeando a si mesma CellAtLocationPk.java

@Embeddable
public class CellAtLocationPk implements Serializable {
private static final long serialVersionUID = 5286485161491158083L;
private Cell servingCell;
private Cell neighbourCell;
private Location location;

@ManyToOne
public Cell getServingCell() {
    return servingCell;
}

public void setServingCell(Cell servingCell) {
    this.servingCell = servingCell;
}

@ManyToOne
public Cell getNeighbourCell() {
    return neighbourCell;
}

public void setNeighbourCell(Cell neighbourCell) {
    this.neighbourCell = neighbourCell;
}

@ManyToOne
public Location getLocation() {
    return location;
}

public void setLocation(Location location) {
    this.location = location;
}

public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;
    CellAtLocationPk that = (CellAtLocationPk) o;
    if (servingCell != null ? !servingCell.equals(that.servingCell) : that.servingCell != null)
        return false;
    if (neighbourCell != null ? !neighbourCell.equals(that.neighbourCell) : that.neighbourCell != null)
        return false;
    if (location != null ? !location.equals(that.location) : that.location != null)
        return false;

    return true;
}

public int hashCode() {
    int result;
    result = (servingCell != null ? servingCell.hashCode() : 0);
    result = 31 * result + (neighbourCell != null ? neighbourCell.hashCode() : 0);
    result = 31 * result + (location != null ? location.hashCode() : 0);
    return result;
}
}

questionAnswers(3)

yourAnswerToTheQuestion