4 Replies Latest reply on Sep 4, 2010 3:34 PM by Marcin Misiewicz

    Problems with serialization of the inherited entity properties.

    Marcin Misiewicz Newbie

      Hi

       

      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 ?