6 Replies Latest reply on Jan 11, 2009 12:05 AM by tony.herstell1

    Embedded bypasses Hibernate validation but only in create

    tony.herstell1
      @Embedded
      



      bypasses Hibernate validation but only in create




      @Embedded
      private Sponsors sponsorDetails;
      



      with


      @Embeddable
      public class Sponsors implements Serializable {
      
              @NotNull(message="required")
              private String sponsorDescription;
              @OneToMany(cascade={CascadeType.ALL})
              private List<User> sponsors;
      



      can be created with no sponsorDescription, but upon update it fails a mandatory check for sponsorDescription.


      ODD!


      No idea who to raise this with...

        • 1. Re: Embedded bypasses Hibernate validation but only in create
          tony.herstell1

          Should I riase this in the EJB3, JPA or even Hibernate forums?


          I have wroked round it, but it may catch someone out so its useful having it noted.

          • 2. Re: Embedded bypasses Hibernate validation but only in create

            Tony,


            Are you able to reference your embedded object as a secondary-class of Sponsors using Seam and JSF?


            For example, if you have cvSponsor in a session bean as a Sponsor object, as such...


            @In
            private Sponsor cvSponsor;


            And, in your JSF, can you reference cvSponsor.sponsorDetails.<some_attribute>?



            Thanks.

            • 3. Re: Embedded bypasses Hibernate validation but only in create
              tony.herstell1

              If I understand you...Yes.
              These embedded tables just pop the fields into the object as if they are part of the table.. (On MYSQL database it does add them to the table directly).


              Saved me a lot of time re-adding them to all by beans anyhow.


              Some of my beans, where relevant, now have a CreationDate, DateEffectiveFrom, DateEffectiveTo...


              I think I could have just had all my entities extend a base entity and it would have picked up these fields too... but it was something I found that I didn't know about so it had to be played with :) and it meant I didn't have trees of inheritance to get all the common bits I needed in each class.


              given:



              @SuppressWarnings("serial")
              @Embeddable
              public class MaintenanceDates implements Serializable {
              
                  @NotNull
                  @Temporal(TemporalType.DATE)
                  private Date dateEffectiveFrom;
                  @Future
                  @Temporal(TemporalType.DATE)
                  private Date dateEffectiveTo;
                  @NotNull
                  @Temporal(TemporalType.DATE)
                  private Date creationDate = new Date();
              
                  public MaintenanceDates() {
                  }
              





              See Maintenance Dates below....



              /** 
               * @author Tony Herstell 
               * @version $Revision: 1.14 $ $Date: 2008-12-31 07:04:20 $ 
               */ 
              @SuppressWarnings("serial")
              @Entity
              @Name("user")
              @Role(name="userSearchCriteria", scope=SESSION)
              public class User implements Serializable {
                  
                  @Id
                  @GeneratedValue
                  private Long id;
                  @Version
                  @Column(name="version4OptLock")
                  private Integer version; // Hiberante Docs: EJB3 sais Timestamp actually but recommend Integer
                  @NotNull(message="required")
                  @Length(max = 30)
                  private String surname;
                  @NotNull(message="required")
                  @Length(max = 30)
                  private String firstname;
                  @NotNull(message="required")
                  private String password;
                  @NotNull(message="required")
                  @Email
                  private String email;
                  @NotNull
                  private boolean emailContactOk = true;
                  @NotNull(message="required")
                  @Length(min = 8, max = 20)
                  private String homePhone;
                  @Length(min = 8, max = 20)
                  private String mobilePhone;
                  @NotNull
                  private boolean phoneContactOk = true;
                  @NotNull
                  private boolean dressageJudge = false;
                  @NotNull
                  private boolean dressageWriter = false;
                  @NotNull
                  private boolean dressageHelper = false;
                  @NotNull
                  private boolean sjJudge = false;
                  @NotNull
                  private boolean sjHelper = false;
                  @NotNull
                  private boolean showingJudge = false;
                  @NotNull
                  private boolean showingHelper = false;
                  @NotNull
                  private boolean eventsHelper = false;
                  @NotNull
                  private boolean termsApproved = false;
                  @OneToMany(cascade={CascadeType.ALL})
                  private List<SelwynEquestrianCentreRole> roles;
                   @OneToOne(fetch = FetchType.LAZY, cascade={CascadeType.ALL})
                  @JoinColumn(name = "avatar_id")
                  private Image avatar;
                   @Embedded
                  private MaintenanceDates maintenanceDates;
                  @OneToMany(cascade={CascadeType.ALL})
                  private List<Booking> bookings;
                  @Temporal(TemporalType.DATE)
                  private Date dateOfBirth; // Used to ensure a Rider is a Junior Rider etc.
                   @Pattern(regex = "^\\d*$")
                  private Integer esnzRegistrationNumber;




              See Dates below is how I reference them from the Code...


                  @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                  @Begin
                  public String startRegistration() {
                      log.info(">startRegistration");
                      log.info("Starting Registration conversation.");
                      if (conversation != null) {
                          log.info("Conversation. (" + conversation.getId() + ")");
                      }
                      MaintenanceDates dates = new MaintenanceDates();
                      dates.setDateEffectiveFrom(new Date());
                      dates.setCreationDate(new Date());
                      user.setDates(dates);
              
                      /* The user won't have an image so add one that we may use */
                      Image image = new Image();
                      user.setAvatar(image);
              
                      log.info("<startRegistration");
                      return "userRegister";
                  }





              See Dates below is how I reference them from the XHTML EL Code...



              <rich:column sortBy="#{eachUser.dates.creationDate}" rendered="#{userListController.isShowingDates() eq true}">
                   <f:facet name="header">
                        <h:outputText value="Creation Date" />
                   </f:facet>
                   <h:outputText value="#{eachUser.dates.creationDate}">
                        <s:convertDateTime pattern="dd/MMM/yyyy"/>
                   </h:outputText>
              </rich:column>
              




              I hope that is what you were after.


              • 4. Re: Embedded bypasses Hibernate validation but only in create

                Thanks, Tony...looks like I'm missing a constructor on my Embeddable object.  I wish the documentation was a little more clear on Embeddable objects, since I've seen them implemented a variety of different ways (I guess that is a good thing).


                I'll try to match my implementation to be a closer match to your's and see how it goes.


                Thanks for the quick reply, I appreciate it.

                • 5. Re: Embedded bypasses Hibernate validation but only in create
                  tony.herstell1

                  Good Luck!


                  I found this very helpful!


                  EJB Quick Reference Guide


                  but then I was an an EJB3 virgin.


                  I not sure its even for the JBoss's Implementation!



                  I have even used the inheritance stuff (see @DiscriminatorValue)!


                  @SuppressWarnings("serial")
                  @Entity
                  @Name("bookingResourceWithHours")
                  @DiscriminatorValue("WithHours")
                  public class BookingResourceWithHoursRange extends BookingResource implements Serializable {



                  Ill post more code if you need it.



                  Don't forget to give me some points if I deserve them. I like to feel I contribute.

                  • 6. Re: Embedded bypasses Hibernate validation but only in create
                    tony.herstell1

                    OK, just had a very weired error.


                    On latest formal Seam (stock EJB3, JPA etc.), Facelets, RF, etc.


                    My el could not see the embedded fields at all! (it didn't report that the object being embedded with the fields in it was null either which was really confusing - see later as it doesnt actually seem to care!).


                    I then added some code to actually create a sponsors object and attach it... (thinking I would sweep away all pre-created ones)
                         


                    /* (non-Javadoc)
                      * @see nz.co.selwynequestriancentre.action.eventsManagement.EventsManagementController#createEvent()
                      */
                       @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                       @Override
                       public String createEvent() {
                              log.info(">createEvent");
                              event = new Event();
                              mode = Mode.CREATE;
                              event.setEventWorkflowStateKind(EventWorkflowStateKind.SETUP);
                              Sponsors sponsors = new Sponsors();
                              event.setSponsorDetails(sponsors);
                              log.info("<createEvent");
                             return null;
                        }



                    but it just worked.


                    NOW what is REALLY weired is that this code was not called!!! I was doing a view on an existing one. The code was just in the same controller.


                    I wonder is seam (or something) is parsing the code to do something with embedded objects.


                    Head-Melt!