-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Can't make Group Sequence work on annotated list elements
PostPosted: Wed Feb 16, 2011 10:52 pm 
Newbie

Joined: Thu Feb 10, 2011 8:31 am
Posts: 4
Hello,
I am hoping someone could advise as to how I can enforce ordering of constraints on List<WrappedString> elements...

I am using HV-4.1.0 and am trying to do a syntax check, followed by a semantic check on each element of a list.
The element type is a wrapped String, to enable annotation. I am using a GroupSequence in order to enforce the check.

The issue is the following, using a 2 element list as an example: when the first element passes the syntactic check but fails the semantic check, and the second fails syntactically, the first element's semantic check violation is ignored:

list element 1 input: <syntax OK> <semantic failure> --> no error reporting when a semantic error should occur
list element 2 input: <syntax failure> --> syntax failed error

A similar setup with regular String field annotations works as expected - it sounds like the fact that elements of a list impact others.

Thanks for any advice. Code follows.
Code:
//Element type
public class HobbyString {
@ValidHobby( groups = { HobbySyntaxCheck.class}) //composed constraint with @ReportAsSingleViolation
@WorthyHobby( groups = { WorthyHobbyCheck.class}) //same as above
String hobby;
//getter, setter methods
}
//Sample constraint and validator
//..composing constraints + @Constraint, etc
public @interface @ValidHobby {
     class Validator implements ConstraintValidator<ValidHobby, String> {
          //initialize() does nothing
          //isValid() does nothing and returns true, delegating to composing constraints
     }
}
//Group sequence interface
@GroupSequence( { HobbySyntaxCheck.class, WorthyHobbyCheck.class})
public interface HobbyCheck {}
[color=#4040BF]//Bean class[/color]
public class Hobbyist {
  @Valid
  List<HobbyString> hobbies; 
  //getters/settes...
}
//client code
Hobbyist myHobby = new Hobbyist();
//fill a new List<HobbyString> and set myHobby.hobbies with it
//...
validate( myHobby, {HobbyCheck.class}) //should enforce sequence for each element


Top
 Profile  
 
 Post subject: Re: Can't make Group Sequence work on annotated list elements
PostPosted: Thu Feb 17, 2011 7:46 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
The problem is that the sequence is not propagated to the list. You are evaluating a Hobbyist with the HobbyCheck sequence. That means that first all HobbySyntaxCheck constraints are cascaded and then all WorthyHobbyCheck constraints. It is not the group sequence which is applied to each element in your set.

I think what you want to do is to redefine the default group sequence for HobbyString to be HobbySyntaxCheck followed by WorthyHobbyCheck and then just validate default. Then when the default group is validated on your HobbyString the overridden default group sequence kicks in.

--Hardy


Top
 Profile  
 
 Post subject: Re: Can't make Group Sequence work on annotated list elements
PostPosted: Fri Feb 18, 2011 9:56 am 
Newbie

Joined: Thu Feb 10, 2011 8:31 am
Posts: 4
Thank you Hardy, that worked beautifully...this is a great API.

Just a few related questions I would like to ask here - let me know if I need to make new topics instead.

1) This is minor, but for some reason with this solution I saw double messages for each error, but it could be related to Spring.
Is there something in the setup that could cause JSR303 to validate twice? For example, a constraint belonging to more than one group
from those marking the current constraints?

2) I have another requirement which I wonder is doable using separate constraints/validators:

The Hobbyist also has a bean-level constraint, HasNoDuplicateHobby, which raises a violation for each duplicate in the list.
This works well on its own, but I would like to make it part of the syntaxCheck-duplicateCheck-semanticCheck group sequence.
Is this possible, using the existing code? I would think not, and that a custom single top-level constraint is necessary which performs all the checks
within isValid(), navigating the tree up and down as needed.

3) Regarding navigation within the object graph using ConstraintValidatorContext, in the below code
from the HasNoDuplicateHobby constraint validator's isValid(), does the context get reset after each .addConstraintViolation()?
I think the answer is yes (otherwise the path would become corrupted at the next iteration)? Relatedly, is the invocation to
disableDefaultConstraintViolation() necessary after each addConstraintViolation()? I am just trying to grasp better how navigation
works:
Code:
    //...HasNoDuplicateHobby's constraint validator's isValid() invoked on a hobbyist target
      boolean valid = true;
      List<HobbyString> list = ((Hobbyist )target ).getHobbies();
      outer: for ( int i = 0; i < list.size(); i++)
        for ( int j = 0; j < i; j++) {
          HobbyString current = list.get( i);
          if ( list.get(j).equals( current)) {
            //mark current as a violator
            valid = false;
            ctx.disableDefaultConstraintViolation();
            ctx.buildConstraintViolationWithTemplate( "duplicates not allowed").addNode("hobbies")
                .addNode( "hobby").inIterable().atIndex( i)
                .addConstraintViolation();
            continue outer;
          }
        }
      return valid;


Top
 Profile  
 
 Post subject: Re: Can't make Group Sequence work on annotated list elements
PostPosted: Thu Feb 24, 2011 5:31 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Sorry for the late reply. This might be a little late, but I still will quickly answer your questions:
Quote:
1) This is minor, but for some reason with this solution I saw double messages for each error, but it could be related to Spring.
Is there something in the setup that could cause JSR303 to validate twice? For example, a constraint belonging to more than one group
from those marking the current constraints?

No, there should not be multiple error messages. Try isolating the problem from Spring. If the problem persists just using Validator (eg in a unit test case) you should post again all the code and we can have another look.

Quote:
2) I have another requirement which I wonder is doable using separate constraints/validators:

The Hobbyist also has a bean-level constraint, HasNoDuplicateHobby, which raises a violation for each duplicate in the list.
This works well on its own, but I would like to make it part of the syntaxCheck-duplicateCheck-semanticCheck group sequence.
Is this possible, using the existing code? I would think not, and that a custom single top-level constraint is necessary which performs all the checks within isValid(), navigating the tree up and down as needed.

A custom constraint seems to be the way to go here. I don't think you need a bean level constraint though. You can write a custom constraint for List<HobbyString> directly if you want. To detect duplicates in the list you wouldn't need the Hobbyist instance, right?

Quote:
3) Regarding navigation within the object graph using ConstraintValidatorContext, in the below code
from the HasNoDuplicateHobby constraint validator's isValid(), does the context get reset after each .addConstraintViolation()?
I think the answer is yes (otherwise the path would become corrupted at the next iteration)? Relatedly, is the invocation to
disableDefaultConstraintViolation() necessary after each addConstraintViolation()? I am just trying to grasp better how navigation
works:
Code:
    //...HasNoDuplicateHobby's constraint validator's isValid() invoked on a hobbyist target
      boolean valid = true;
      List<HobbyString> list = ((Hobbyist )target ).getHobbies();
      outer: for ( int i = 0; i < list.size(); i++)
        for ( int j = 0; j < i; j++) {
          HobbyString current = list.get( i);
          if ( list.get(j).equals( current)) {
            //mark current as a violator
            valid = false;
            ctx.disableDefaultConstraintViolation();
            ctx.buildConstraintViolationWithTemplate( "duplicates not allowed").addNode("hobbies")
                .addNode( "hobby").inIterable().atIndex( i)
                .addConstraintViolation();
            continue outer;
          }
        }
      return valid;

You don't have to call disableDefaultConstraintViolation() every time and the path resets.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.