1 2 Previous Next 19 Replies Latest reply on Mar 5, 2007 8:33 AM by krica

    Problem: Custom validate methods in EJBs crash

    bfo81

      Well, custom validators belong to a real-life JSF web apllication like coffee to a good start into the day ;).

      Let's take an example (there are many occurences of such a situation in my current app, but I love easy examples *g*):

      - Entity Person
      - has a n:m relation to multiple other persons (friends)
      - has a relation to one specific person (best_friend)

      When editing/creating a person you pick his/her friends from a list of persons (SelectManyMenu) and the best friend, too, (but from a SelectOneMenu).

      So far so good, that was easy. BUT: There is an important constraint: The best_friend must be one of your friends, of course. So it's important to check this before saving.

      There are two possibilities:

      - In the action method ("store"): If best_friend is not contained in friends, add an error message, mark the transaction as rollback-only and redisplay the page (empty outcome: return null). Works, but it's UGLY

      - In a custom JSF validator: BEAUTIFUL :)

      Problem: The custom validator (that would be added to the best friend's SelectOneMenu) needs not only be aware of the best friend, but also of the list of friends. It's a "complex" validator (if I may call it like this), since it needs more information than only the status of the field it belongs to.

      Possible Solution: Add a validateBestFriend(FacesContext, UIComponent, Object) method to the PersonEditorBean (SFSB), which holds the state of the edited person. So there the validator method has access to all the information it needs and can perform the check. If you select a "non-friend" as best friend, it throws a ValidatorException.

      New problem: The ValidatorException is caught by the Stateful Bean and the app crashed with an exception report. The ValidatorException is not passed through to JSF as EJB3 intervenes. DAMN!

      So any idea how to make EJB3 ignore the Exception and pass it through? Or how to have such a "complex" validation performed in an other way?

      I'd be thankful for any answer :).

        • 1. Re: Problem: Custom validate methods in EJBs crash
          bfo81

          Well, forget it. There's another problem.

          That "complex" validation would work well on an existing person that you edit.

          But when you create a new person all its properties are null. And when you fill in the fields in a form and click save, then the persons properties are still null during validation (phase 3). They get their concrete values later, in phase 4 (update model values). And, alas, you cannot compare something to null.

          So this is a killer for the idea of validators that should know "more" than just one field.

          • 2. Re: Problem: Custom validate methods in EJBs crash
            pmuir

            IMO this is a (big) problem with JSF validation - not that the validation framework can only handle 'simple' validation, but that you can't display 'complex' validation errors at the same time as simple ones. I can't see a way around it. I wonder if there has been any disucssion about this on other JSF fora (myfaces, facelets, glassfish) and whether any JSF component libraries have found a way around it.

            • 3. Re: Problem: Custom validate methods in EJBs crash
              raja05

               

              "bfo81" wrote:

              But when you create a new person all its properties are null. And when you fill in the fields in a form and click save, then the persons properties are still null during validation (phase 3). They get their concrete values later, in phase 4 (update model values). And, alas, you cannot compare something to null.


              Take a look at the ModelValidator class in org.jboss.seam.ui. That does its validation at the process Validation phase by using the model class (and the validators that go along with it) and the values that are in the request.

              One other way is that since the values are updated in the model only later(after the processValidations), you could queue a new type of event and set the phaseid of that to be UPDATE_MODEL_VALUES. That way the event will be queued during validations but will only be processed after the model values are updated. Thats still ugly(as you are validating in a phase thats not meant for that ) but will work.


              • 4. Re: Problem: Custom validate methods in EJBs crash
                pmuir

                AFAIK the ModelValidator doesn't solve the 'complex' validation case: when you want to validate the value of component x against the value of component y. A simple example of this is that the integers entered into X and Y must add up to > 150.

                • 5. Re: Problem: Custom validate methods in EJBs crash
                  gavin.king

                  IMO, it is perfectly reasonable to put "complex" validations in the action method...

                  • 6. Re: Problem: Custom validate methods in EJBs crash

                    I agree with Gavin. I've always been ok with complex validation in the action method (or control flow). If you need something a little more declarative, it shouldn't be too hard to use Seam plus EJB interceptors to write your thin framework.

                    If you think about it this is what JSF is doing anyway with its phased approach to conversion and validation. Being able to use EJB 3 allows you to slip in your own layer immediately preceeding action invocation. You'd then be able to apply any declarative application concerns, including validation, on objects that had already been converted and validated in isolation.

                    Would it help if Seam provided a "standard" annotation that highlights this ability or should users just implement something like this on their own? I guess if this feature is being requested, giving the masses what they want may have some value, even if it's just providing a utility that they could provide themselves. Utility is a good thing.

                    • 7. Re: Problem: Custom validate methods in EJBs crash
                      gavin.king

                      There is one problem with performing validation during the action phase: if you are using an extended persistence context, you would prefer to do validation before applying values onto the model object. But by the time we get to the action method, the values have already been applied. It is then difficult to roll back the change to prevent them being written to the database.

                      However, there is a solution: if you use an extended persistence context with manual flushing, you are fine. There is better support for this in CVS.

                      • 8. Re: Problem: Custom validate methods in EJBs crash
                        pmuir

                        I still think that it is frustrating that JSF validator error messages and action phase validation error messages won't appear at the same time. Any ideas?

                        • 9. Re: Problem: Custom validate methods in EJBs crash

                          And required checking happens outside of conversion/validation at yet another time. Unfortunately, JSF seems to be designed to support providing a consistent checked state through each phase of the lifecycle and short circuit phases if there are problems. This almost explicitly designs away your desire to collect all this information and display it at once.

                          I don't see a JSF provided solution to this problem in 1.2 (Gavin has mucked more with the internals though, maybe he knows better). It seems to me the easiest solution would be to ditch JSF validation and simply validate yourself within the application. Use the framework or not, but don't fight it.

                          There may be a way to reuse your existing validator classes and write a custom phase listener that would provide your own hooks to the validation phase, but then you'd be using your own validator framework and not JSFs (no UI component tie in). I just don't think JSF was designed to give you what you want.

                          • 10. Re: Problem: Custom validate methods in EJBs crash
                            gavin.king

                            Unfortunately this piece of JSF is not really as customizable as I would like. For example, I really hate having to use required=true for an @NotNull attribute, but not much I can do there....

                            • 11. Re: Problem: Custom validate methods in EJBs crash
                              pmuir

                              I see where you are coming from with validating within the application but IMO the disadvantages are greater

                              • Your entities get updated with invalid values (less of an issue with manual flushing as Gavin says)
                              • That's what @Invalid did and IIRC it didn't work brilliantly
                              • As you say, harder to attach errors to the correct component on the page (the ease with which this is possible in JSF is, IMO, one of its real strengths)
                                In JSF 1.2 there is the findComponent method available; using this it could be possible to get another component, retrieve it's value and use it. It wouldn't really fit with the validator annotations but could be good for custom validators. I will stew on it.

                                The only way I found around the NotNull/required problem is to have a ModelValidator as a component and, if the notnull annotation is on it's parent's value, automatically sets required=true on it's parent; I did have something like this working in my version of ModelValidator but then dumped it as I felt that (in my application) whether a field was required or not was up to the view not the Entity (e.g. a customer is required to enter more details than a account manager when setting up a new account)


                              • 12. Re: Problem: Custom validate methods in EJBs crash
                                denis-karpov

                                1. For simple validation (just value) we can still use JSF validation.

                                2. For complex validation I use drools (jBoss Rules).
                                It nicely integrated with Seam Page Flow (see seam samples).

                                You can express your validation in rule set. IMHO it looks like quite elegantly. You can define as complex rules as you want. And validation logic is separated.

                                And most important, it works steadily. I have not experienced any problems yet.

                                Denis.

                                • 13. Re: Problem: Custom validate methods in EJBs crash
                                  bfo81

                                   

                                  "gavin.king@jboss.com" wrote:
                                  There is one problem with performing validation during the action phase: if you are using an extended persistence context, you would prefer to do validation before applying values onto the model object. But by the time we get to the action method, the values have already been applied. It is then difficult to roll back the change to prevent them being written to the database.

                                  However, there is a solution: if you use an extended persistence context with manual flushing, you are fine. There is better support for this in CVS.

                                  Here's another way, which works already now without having to wait for Seam 1.1 or using the CVS version;).

                                  
                                  import javax.ejb.SessionContext;
                                  
                                  @Resource
                                  SessionContext ejbCtx;
                                  
                                  public String actionMethod() {
                                  ...
                                   if (validationFailed)
                                   ejbCtx.setRollbackOnly();
                                  ...
                                  }


                                  By the way: To prevent the Extended Persistence Context from auto-flushing where you maybe do not expect it, annotate your class with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) so that no storing will be performed. And to make your save-method work again, annotate it with @TransactionAttribute(TransactionAttributeType.REQUIRED)

                                  • 14. Re: Problem: Custom validate methods in EJBs crash
                                    gavin.king

                                    Unfortunately this is not a solution. The EPC is considered "hosed" after a transaction rollback.

                                    The only way (per-spec) is to annotate actionMethod() or the bean as @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), which is ugly.

                                    CVS version of Seam has @Begin(flushMode=FlushMode.MANUAL) as a much cleaner alternative.

                                    1 2 Previous Next