1 Reply Latest reply on Dec 17, 2009 9:13 PM by shsharma79

    Issue with JpaIdentityStore use

      Hi, I am a newbie to Seam. I am working on a simple user registration app where I am trying to use JpaIdentityStore for Identity management. I have followed the steps given in the sample seamspace example. But I am not able to get it working. The main issue is that I have a field userId in my user class which I want to use as the primaryKey for my User table. That is why I have annotated this field with @Id and @GeneratedValue. Now, when I am trying to invoke identityManager.createUser() method, everything goes fine until when IdentityManager invokes HibernateEntityManager to persist the new user. At that point, I am getting an exception that userId field is null. As I have put @GeneratedValue annotation on the field, I am expecting this value to be auto-generated but that's not the case. Any help will be appreciated. Here are the code artifacts:



      User.java
      
      @Entity
      @Name("user")
      @Scope(ScopeType.SESSION)
      public class User implements Serializable{
          private Long userId;
          private String emailAddress;
          private String firstName;
          private String middleInitial;
          private String lastName;
          private String password;
          private int age;
          private List<Role> roles;
      
          public User(Long userId, String emailAddress, String firstName,
                      String mi, String lastName, String password, int age) {
              this.userId = userId;
              this.emailAddress = emailAddress;
              this.firstName = firstName;
              this.middleInitial = mi;
              this.lastName = lastName;
              this.password = password;
              this.age = age;
          }
      
          public User() {}
      
          @Id @GeneratedValue
          public Long getUserId() {
              return userId;
          }
      
          public void setUserId(Long userId) {
              this.userId = userId;
          }
      
          @UserPrincipal
          @NotNull @Email @Column(unique = true)
          public String getEmailAddress() {
              return emailAddress;
          }
      
          public void setEmailAddress(String emailAddress) {
              this.emailAddress = emailAddress;
          }
      
          @NotNull
          @Length(min = 1, max = 30)
          @UserFirstName
          public String getFirstName() {
              return firstName;
          }
      
          public void setFirstName(String firstName) {
              this.firstName = firstName;
          }
      
          @Length(max = 1)
          public String getMiddleInitial() {
              return middleInitial;
          }
      
          public void setMiddleInitial(String middleInitial) {
              this.middleInitial = middleInitial;
          }
      
          @NotNull
          @Length(min = 1, max = 30)
          @UserLastName
          public String getLastName() {
              return lastName;
          }
      
          public void setLastName(String lastName) {
              this.lastName = lastName;
          }
      
          @UserPassword(hash = "md5")
          @NotNull
          @Length(min = 6, max = 14)
          public String getPassword() {
              return password;
          }
      
          public void setPassword(String password) {
              this.password = password;
          }
      
          @NotNull
          @Range(min = 18, message = "You must be 18 or older to register.")
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @UserRoles
          @ManyToMany(fetch = FetchType.EAGER)
          @JoinTable(
              joinColumns = { @JoinColumn(name = "USER_ID") },
              inverseJoinColumns = { @JoinColumn(name = "ID")}
          )
          public List<Role> getRoles() {
              return roles;
          }
      
          public void setRoles(List<Role> roles) {
              this.roles = roles;
          }
      }
      
      RegisterAction.java
      
      @Stateful
      @Name("register")
      @Scope(ScopeType.EVENT)
      public class RegisterAction implements Register{
          @Logger private Log log;
      
          @In private User user;
          @In private IdentityManager identityManager;
          @In private StatusMessages statusMessages;
          @In EntityManager entityManager;
      
          private boolean registered;
          private String verifyPassword;
      
          public void register() {
              if(verifyPassword.equals(user.getPassword())) {
                  // Try to persist the user so that we can get the id generated for it
      //            entityManager.persist(user);
                  try {
                      new RunAsOperation() {
                          public void execute() {
                              identityManager.createUser(user.getEmailAddress(),
                                      user.getPassword(), user.getFirstName(),
                                      user.getLastName());
                          }
                      }.addRole("admin").run();
                      statusMessages.add("User #0 #1 registered successfully.",
                              user.getFirstName(), user.getLastName());
                      registered = true;
                  } catch (IdentityManagementException e) {
                      statusMessages.add(e.getMessage());
                  }
              } else {
                  statusMessages.addToControl("verifyPassword",
                          "Verify Password does not match the Password.");
                  verifyPassword = null;
              }
          }
      
          @Observer(JpaIdentityStore.EVENT_PRE_PERSIST_USER)
          public void onPrePersist(User user) {
              log.info("***** Pre-persist observer called. Setting user properties *****");
              user.setMiddleInitial(this.user.getMiddleInitial());
              user.setAge(this.user.getAge());
              log.info("***** User properties set *****");
          }
      
          public String getVerifyPassword() {
              return verifyPassword;
          }
      
          public void setVerifyPassword(String verifyPassword) {
              this.verifyPassword = verifyPassword;
          }
      
          public boolean isRegistered() {
              return registered;
          }
      
          public void setRegistered(boolean registered) {
              this.registered = registered;
          }
      
          public void invalid() {
              statusMessages.add("Validation failed. Please try again");
          }
      
          @Remove @Destroy
          public void destroy() {}
      }
      
      Components.xml
      
      ....
      ....
         <security:jpa-identity-store
                 entity-manager="#{entityManager}"
                 user-class="com.shal.seam.entity.User"
                 role-class="com.shal.seam.entity.Role"/>
      ....
      ....
         <persistence:managed-persistence-context name="entityManager"
                                           auto-create="true"
                            persistence-unit-jndi-name="java:/validationEntityManagerFactory"/>
      ....
      ....
      
      And here is the exception:
      
      ....
      ....
      Caused by: javax.persistence.PersistenceException: org.hibernate.AssertionFailure: null id in com.shal.seam.entity.User entry (don't flush the Session
       after an exception occurs)
              at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:527)
              at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:114)
              at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:247)
              at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:86)
              at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:177)
              at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1389)
              ... 54 more
      Caused by: org.hibernate.AssertionFailure: null id in com.shal.seam.entity.User entry (don't flush the Session after an exception occurs)
              at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:55)
              at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:164)
              at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:120)
              at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
              at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
              at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
              at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
              at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
              at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:515)
              ... 59 more




        • 1. Re: Issue with JpaIdentityStore use

          I have figured out the issue. It's because of the @Length annotation on the password field in User.java. As I was using the same password field for the hashed password as well, the hashed password generated by JpaIdentityStore was outside the max bound of the field. This was causing a validation error on the entity during the persist phase which was happening before generateId phase.


          So, I created another property in User.java, called passwordHash and annotated that with @UserPassword annotation. It works fine now.


          Thanks
          Shalandra