Problems with serialization of the inherited entity properties.
misqu23 Aug 10, 2010 12:56 PMHi
I've got serious problems with serialization of my entities. Here is the sample entity which is not serialized :
package pl.scentia.smartoffice.persistence.pojo.assignments; import java.io.Serializable; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.jboss.errai.bus.server.annotations.ExposeEntity; /** * @author Marcin Misiewicz * */ @Entity @ExposeEntity public class SimpleEntity extends AbstractAssignment implements Serializable { private static final long serialVersionUID = -2024995029998485978L; @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="ID") private Long id; @Column(name="ACTIVE",nullable=false) private boolean active = true; @Column(name="LOGIN",unique=true) @Size(min=4) private String login; @Column(name="PASSWORD",nullable=false) @Size(min=4) private String password; @OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="USER_ID") @NotNull @Valid private Set<UserRole> userRoles; /** * @return the login */ public String getLogin() { return login; } /** * @param login the login to set */ public void setLogin(String login) { this.login = login; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the id */ public Long getId() { return id; } /** * @param id the id to set */ public void setId(Long id) { this.id = id; } /** * @return the userRoles */ public Set<UserRole> getUserRoles() { return userRoles; } /** * @param userRoles the userRoles to set */ public void setUserRoles(Set<UserRole> userRoles) { this.userRoles = userRoles; } /** * @return the active */ public boolean isActive() { return active; } /** * @param active the active to set */ public void setActive(boolean active) { this.active = active; } /* (non-Javadoc) * @see pl.scentia.smartoffice.persistence.pojo.AbstractEntity#comparePK(java.lang.Object) */ @Override protected boolean comparePK(Object obj) { if (id != null && obj != null) { Long entityId = ((SimpleEntity)obj).getId(); if (entityId!= null && entityId.equals(id)) return true; } return false; } /* (non-Javadoc) * @see pl.scentia.smartoffice.persistence.pojo.AbstractEntity#getPKhashCode() */ @Override protected Long getPKhashCode() { return id; } }
When I compile errai doesn't produce marshalling/demarshalling stuff for this entity. After some investigation I have discovered that when I remove
active property with coresponding getter and setter, errai starts to serialiaze this class. So first of all errai has some problems with serialization of my boolean active property.
But unfortunately it is the only top of the iceberg, as you can see SimpleEntity extends AbstractAssignment, on the other hand AbstractAssignment extends AbstractDocument and so on. When I send SimpleEntity through rpc to the server and I try to read one of the properties inherited from one of the parent class I always get null, it seems that errai doesn't respect inheritance during serialization.
Below I post full object tree :
AbstractAssignment.java
package pl.scentia.smartoffice.persistence.pojo.assignments; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; import pl.scentia.smartoffice.persistence.pojo.AbstractDocument; import pl.scentia.smartoffice.persistence.pojo.OrganizationUnit; @MappedSuperclass public abstract class AbstractAssignment extends AbstractDocument implements Serializable { private static final long serialVersionUID = 2658581482246530051L; @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH}) @JoinColumn(name="SOURCE_ID") private OrganizationUnit sourceUnit; @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH}) @JoinColumn(name="DEST_ID") private OrganizationUnit destinationUnit; public OrganizationUnit getSourceUnit() { return sourceUnit; } public void setSourceUnit(OrganizationUnit sourceUnit) { this.sourceUnit = sourceUnit; } public OrganizationUnit getDestinationUnit() { return destinationUnit; } public void setDestinationUnit(OrganizationUnit destinationUnit) { this.destinationUnit = destinationUnit; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((destinationUnit == null) ? 0 : destinationUnit.hashCode()); result = prime * result + ((sourceUnit == null) ? 0 : sourceUnit.hashCode()); return result; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (this == obj) return true; if (getClass() != obj.getClass()) return false; AbstractAssignment other = (AbstractAssignment) obj; if (destinationUnit == null) { if (other.destinationUnit != null) return false; } else if (!destinationUnit.equals(other.destinationUnit)) return false; if (sourceUnit == null) { if (other.sourceUnit != null) return false; } else if (!sourceUnit.equals(other.sourceUnit)) return false; return true; } }
AbstractDocument.java
package pl.scentia.smartoffice.persistence.pojo; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.MappedSuperclass; @MappedSuperclass public abstract class AbstractDocument extends AbstractEntity implements Serializable { private static final long serialVersionUID = -6622420818968606410L; /** * In the default implementation it should be unique as well */ @Column(name="DOC_NUMBER",nullable=true) private String number; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }
AbstractEntity.java
import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.EntityListeners; import javax.persistence.JoinColumn; import javax.persistence.MappedSuperclass; import javax.persistence.OneToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; import pl.scentia.smartoffice.persistence.pojo.assignments.UserAssignment; import pl.scentia.smartoffice.persistence.pojo.externals.EntityAudit; @MappedSuperclass @EntityListeners({EntityAudit.class}) public abstract class AbstractEntity implements Serializable { private static final long serialVersionUID = 6788919395328157695L; @Transient private boolean selected; /** * If entity is in deleted state, set to true. * Defaults to <b>false</b>. */ @Column(name="DELETED",nullable=false) private boolean deleted = false; @OneToOne(cascade={CascadeType.REFRESH}) @JoinColumn(name="OWNER_GROUP_ID",nullable=true) private Group ownerGroup; @Temporal(TemporalType.TIMESTAMP) @Column(name="CREATE_DATE",nullable=false) private Date createDate; @OneToOne(cascade={CascadeType.REFRESH}) @JoinColumn(name="CREATE_USER_ID",nullable=true) private UserAssignment createUser; @Temporal(TemporalType.TIMESTAMP) @Column(name="LAST_MODIFY_DATE",nullable=false) private Date lastModifyDate; @OneToOne(cascade={CascadeType.REFRESH}) @JoinColumn(name="LAST_MODIFY_USER_ID",nullable=true) private UserAssignment lastModifyUser; public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } public boolean isDeleted() { return deleted; } public void setDeleted(boolean deleted) { this.deleted = deleted; } public Group getOwnerGroup() { return ownerGroup; } public void setOwnerGroup(Group ownerGroup) { this.ownerGroup = ownerGroup; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public void setCreateUser(UserAssignment createUser) { this.createUser = createUser; } public UserAssignment getCreateUser() { return createUser; } public Date getLastModifyDate() { return lastModifyDate; } public void setLastModifyDate(Date lastModifyDate) { this.lastModifyDate = lastModifyDate; } public void setLastModifyUser(UserAssignment lastModifyUser) { this.lastModifyUser = lastModifyUser; } public UserAssignment getLastModifyUser() { return lastModifyUser; } public boolean isManaged() { if (getPKhashCode() == null) return false; return true; } protected abstract boolean comparePK(Object obj); protected abstract Long getPKhashCode(); @Override public int hashCode() { final int prime = 1; int result = 1; result = prime * result; if (getPKhashCode() == null) { if (createDate == null) result += super.hashCode(); else result += createDate.hashCode(); } else { result += getPKhashCode().hashCode(); } return result; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (this == obj) return true; if (getClass() != obj.getClass()) return false; return comparePK(obj); } }
Of course standard gwt rpc serialization used in conjuction with gilead is working as expected with those inheritance hierarchy.
I don't know what do I have to change to get it working. I've notice that errai has persistence module but I don't know how to use it, how to configure it and if this module will help ?