Programmatic Bean Validation (JSR 303) without Annotation [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
using Hibernate Validator without calling annotation.
I have this composite constraint annotation (only for illustration):
#Target... #Retention...
#Constraint(validatedBy = {})
#Pattern(regexp = PasswordComplexity.AT_LEAST_TWO_NONE_ALPAH_CHARS)
#Length(min = 6, max = 20)
public #interface PasswordComplexity {
...
}
And I use it in Spring Controllers and Entity Classes.
But now I need to check a single String in a Service method, where I need to apply the same constraint to a single String. Because of the fact that the constraint is the same, I want to use the same definition of the constraint (#PasswordComplexity) (single source of truth). Something like:
public void createUser(UserDto userDto, String password) {
if(hasViolation(validator.validate(password,PasswordComplexity.class))) {
throw new PasswordComplexityViolationException();
} else {
…
}
}
But I do not know how to run the JSR 303 Validator for an not annotated simple object (String). Is it at least possible, and how?
(I use Hibernate Validator as JSR 303 provider)

One way to do this would be write a full custom validator, and push the logic down into that class having the annotation just use the validator. This would mean you then had an independent compilation unit (A full class PasswordComplexityValidator implements implements ConstraintValidator<PasswordComplexity, String> ...) which you could use independently of the annotation. This approach would also make it easier for you to unit test the validation.
However, since you are using the annotation as a way of configuring the existing regex validator provided by Hibernate, you could use that one instead, passing it the constant pattern from the annotation class. You should also be able to package your length constrain into the regex too, which would be simpler and faster than having both annotations anyway.

Related

Java validation of object with annotation directly

The conventional way of java validation is to define a class with properties and annotated with one or many validation constraint annotations such as #NotNull or #Future.
Is it possible to validate an object directly with validator constraint annotation without specifying a class. For example:
String a = "";
validator.validate(a, javax.validation.constraints.NotNull.class);
That's clearly not a use case for which Hibernate Validator has been designed.
What you would have to do is to create a ConstraintValidator from the constraint and the type of the object and then use the isValid() method. The entry point would be ConstraintValidatorManager.
It's an internal class so it's subject to change without warning, even in a micro version so I wouldn't recommend using it.

using javax.validation to validate bean with choices

I'm implementing an in-memory API gateway to a SOAP service utilizing JAXB. One of the schema elements is a "choice", and there are several elements in the choice block.
I'm attempting to mirror the generated JAXB classes in the client namespace, so for this "choice" scenario I have a bean class with several properties, only one of which will be non-null.
I'm attempting to use the #NotNull annotation from javax.validation, along with the ValidatorFactory and Validator. However, a "choice" scenario makes this a little more complicated. I'm guessing this would call for a custom ConstraintValidator, along with a custom annotation to refer to the custom ConstraintValidator.
For instance, here's some fake code that resembles a part of my structure:
public class InquireRandomInformationRequest {
#NotNull(message ="subscriberSelector cannot be null")
#Valid
private SubscriberSelector subscriberSelector; // required
private SelectorMode mode; // optional
...
}
public class SubscriberSelector {
// Choice 1
private String billingAccountNumber; // \d{8,9,12,13}; required
private MarketInfo billingMarket; // optional
// Choice 2
private String subscriberNumber; // \d{10}; required
private ValidationCriteria validationCriteria; // optional
private BillingAccountInformation billingAccountInformation; // optional
private MemoProductType memoProductType; // optional
// Choice 3
private String unifiedBillingAccountNumber; // [0-9A-Za-z]{13}; required
...
}
I understand that I need the #Valid annotation on the "subscriberSelector" property for the validator to validate the sub-object. Past that, I'm not quite sure what I need to do to handle the choices problem.
To fit my example, I will need exactly one of "billingAccountNumber", "subscriberNumber", or "unifiedBillingAccountNumber" to be non-null (although I could compromise on simply taking the first non-null one in a particular sequence). In each "choice group", the other properties are optional, but it's possible that another property could be "required" if that particular choice group is selected (the selector property is non-null, in other words).
I've looked through the Hibernate Validator documentation, but I'm not sure exactly how to apply that for this situation.
If I define a custom annotation and a custom ConstraintValidator, where is the annotation referenced? On the class (like "SubscriberSelector") or on the "subscriberSelector" property (the former seems more logical to me).
You can define constraints on the class or on the property depending on your requirements.
Usually, the constraints are placed on the property but, in the case you mention, as multiple properties are concerned and interdependent, you should place the constraint at the class level.
See https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-declaring-bean-constraints in our documentation.

When to use Bean Validation vs a customized validation framework?

I am validating fields of my Data Access Object classes. In one attempt, I have started adding Bean Validation annotations to the properties (#NotNull, #NotBlank, #Min, #Max and so on). I also have more annotations Jackson (JsonProperty (..)) for swagger library and documentation (#Api (...)). In my opinion the class was very "dirty" with many annotations (each property has at least three annotations). Example of one field:
#JsonProperty("ownName")
#Api(description="it is my own name" required=true)
#Valid
#NotNull
private SomeObject object;
In another attempt, I have performed my own validation with the Spring Validator interface. If a custom validator such as the Spring Interface is used it seems to be cleaner and also allows you freedom to generate more than one validator for different situations. Also, the class does not seem to be so overloaded with annotations and validations are independent of the class. Example of Validator:
public class UserValidator implements Validator {
#Override
public boolean supports(Class<?> arg0) {
return User.class.isAssignableFrom(arg0);
}
#Override
public void validate(Object obj, Errors error) {
User user = (User) obj;
if(user.getPassword().length() < 10)
{
error.reject("Password must be lesser than 10");
}
//more validations....
}
}
When would you use one or another?
What are the pros and cons of each?
I think it is a matter of taste and use case. I agree that sometimes it feels one ends up in some sort of annotation overload.
Some reasons for using Bean Validation are that it is a standard. The constraint annotations are standardized and many frameworks integrate with it, for example JPA in case you want to add yet another annotation based framework ;-)
Using something like Spring binds you to a specific library/framework. Your code will be less portable. If you of course never see a scenario where you would leave Spring behind, this might not matter.
Of course you could do something home grown altogether, but in this case you need to write the whole integration code into for example Spring, REST, JPA, etc.
Also writing a general purpose validation framework is not trivial. There are many things to consider.

Using Java EE 6 Bean Validation

I am trying to use Java EE 6 Validation as specified here
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
I have annotated a simple field
#Max(11)
#Min(3)
private int numAllowed;
The docs says "For a built-in constraint, a default implementation is available" but how do I specify this. My constraints checks are not kicking in. I would expect it to work on calling of the setter method for the field. The only import in my class is
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
How/where do I specify the implementation?
I am putting the constraint on a filed in a simple POJO not an #Entity class, is this ok?
Your use of the annotations is just fine. There's a validator implementation for each of those rest assured.
However, at some point you need to trigger the validation of this POJO. If it were an #Entity it would be your JPA provider which triggers validation, in your case you need to do it yourself.
There's a nice documentation for Hibernate Validator which is the reference implementation for JSR-303.
Example
public class Car {
#NotNull
#Valid
private List<Person> passengers = new ArrayList<Person>();
}
Using Car and validating:
Car car = new Car( null, true );
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
You may also want to read how bean validation is integrated with other frameworks (JPA, CDI, etc.).
Just putting a constraint annotation to a field will not cause its evaluation. Instead some mechanism must trigger validation via the javax.validation.Validator API; this happens transparently e.g. for JPA entities, properties bound to JSF input elements or constrained methods of CDI beans in Java EE 7. If you want to validate an un-managed POJO, you have to invoke the validator yourself.

Where is implementation of #Future defined?

Java persistence & hibernate make it easy to add property-level constraints to entities.
#Entity
#Table(name = "party")
public class PartyEntity {
#Future
public DateTime start;
}
The javax.validation.constraint.Future annotation is defined without a specific implementation.
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {})
public #interface Future {
// ...
}
Where is actual validation implemented? How can this be extended to allow an administrator override?
Though not shown here, I am already using groups for another purpose on this constraint.
Implementations for many validators supplied by hibernate-validator: http://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-usingvalidator.html#validator-defineconstraints-builtin
If you are using Maven just add following dependency to pom.xml file:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.0.Alpha1</version>
</dependency>
How can this be extended to allow an administrator override?
The simplest way is to write your own instead.
JSR 303 validation does not have too much directly to do with JPA. Of course also JPA entities can be validated with it. What it comes to actual question - most likely you want to follow php-coder's advice and implement new annotation and validation of contraints set via annotation usage.
If because of some mysterious reason you really have to change how Future annotation is processed in your implementation, then solution is of course implementation specific. Assuming that you use Hibernate Validator 4.3, actual check of validation constraint takes place in:
org.hibernate.validator.internal.constraintvalidators.FutureValidatorForDate
org.hibernate.validator.internal.constraintvalidators.FutureValidatorForCalendar
How these implementations get picked can be affected in org.hibernate.validator.internal.metadata.core.ConstraintHelper. I suggest to attach sources of implementation you use to your IDE, because then it is easy to navigate to this kind of details.

Categories

Resources