Using Java EE 6 Bean Validation - java

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.

Related

Validation through "mixins"

I am developing a RESTful API in Spring Boot 2+, for which I need to perform several validations. Nothing really fancy, just the typical #NotNull, #NotEmpty, #Max, #Min, #Email, #Regex, #Future, etc stuff...
Except that I have beans from an API that I must use yet cannot modify. This means that I cannot annotate the fields and methods in those DTOs.
It would be great if I could create mixin-like classes or interfaces with the same structure of the real DTOs I must use in the API, on which I would happily place bean-validation's annotations.
For example, if I had the following DTOs that I couldn't modify:
public class Person {
private String name;
private String dateOfBirth;
private Address address;
// constructors, getters and setters ommited
}
public class Address {
private String street;
private String number;
private String zipCode;
// constructors, getters and setters ommited
}
I would create the following 2 interfaces that mimic their structure and annotate them as I need:
public interface PersonMixin {
#NotBlank String name();
#Past String dateOfBirth();
#Valid #NotNull Address address();
}
public interface AddressMixin {
#NotBlank String street();
#Positive int number();
#NotBlank String zipCode(); // Or maybe a custom validator
}
As you see, the name of the methods in the interfaces match the names of the properties of the bean classes. This is just one possible convention...
Then, ideally, somewhere while the app is loading (typically some #Configuration bean) I would be very happy to do something along the lines of:
ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);
Except that ValidationMixinsSetup.addMixinFor is pure fantasy, i.e. it doesn't exist.
I know that there exists a similar construct for Jackson regarding JSON serialization/deserialization. I've found it extremely useful many times.
Now, I've been looking at both Spring and Hibernate Validator's source code. But it's not a piece of cake... I've dug into ValidatorFactory, LocalValidatorFactoryBean, TraversableResolver implementations, but I haven't been able to even start a proof-of-concept. Could anyone shed some light into this? I.e. not how to implement the whole functionality, but just how and where to start. I'm after some hints regarding which are the essential classes or interfaces to extend and/or implement, which methods to override, etc.
EDIT 1: Maybe this approach is not the best one. If you think there's a better approach please let me know.
EDIT 2: As to this approach being overly complicated, too convoluted, Rube Goldberg, etc, I appreciate and respect these points of view, but I'm not asking whether validation through mixins is good or bad, convenient or inconvenient, neither why it might be like so. Validation through mixins has pros on its own and I think it could be a good approach for some valid use cases, i.e. having declarative validation instead of scripted or programmatic validation while also separating validation from the model, letting the underlying framework do the actual validation job while I only specify the constraints, etc.
Using programmatic API (as mentioned in the comment) in case of Person you could apply next mappings for your constraints:
HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();
ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( Person.class )
.field( "name" )
.constraint( new NotNullDef() )
.field( "number" )
.constraint( new PositiveDef() )
.field( "address" )
.constraint( new NotNullDef() )
.valid();
Validator validator = config.addMapping( mapping )
.buildValidatorFactory()
.getValidator();
And as you are using Spring - you would need to do that in one of your sping config files where you define a validator bean.

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.

Getting value of attribute specified in JPA annotation

Assuming that I have some entity with a field annotated as follows:
#Column(name="title", length=255)
private String title;
how could I get the value of the 'length' attribute with Java?
Hibernate Validator (the reference implementation of the Bean Validation specification) can be used to do this type of validation without implementing your own annotation-based validator. Integration with JPA allows to execute the validation during the persist or update of an entity. It's an Hibernate project, but it can be used with other JPA providers like EclipseLink.
Using reflection try something like this.
Class<?> cls = Class.forName(name);
Annotation ety = cls.getAnnotation(Column.class);
int value1 = a.length();
Although this can be done with the code above. I don't recommend use reflections to do this at all.
Try to use JSR-303 and javax.validation.constraints, there are pretty easy to use.

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

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.

Unique constraint with JPA and Bean Validation

I'd like to have a #Unique constraint with Bean Validation, but that is not provided by the standard. If I would use JPA's #UniqueConstraint I wouldn't have a unique validation and error reporting mechanism.
Is there a way to define #Unique as a Bean Validation constraint and combine it with JPA, such that JPA creates a column with an unique constraint and checks wheter a value is unique or not?
Unless you acquire a lock on a whole table, it is basically not possible to check for unicity using a SQL query (any concurrent transaction could modify data after a manual check but before the commit of the ongoing transaction). In other words, it isn't possible to implement a valid unique verification at the Java level and thus to provide a validation implementation. The only reliable way to check for unicity is while committing the transaction.
The BV spec summarizes it like this:
Appendix D. Java Persistence 2.0 integration
Question: should we add #Unique that
would map to #Column(unique=true)?
#Unique cannot be tested at the Java
level reliably but could generate a
database unique constraint generation.
#Unique is not part of the BV spec
today.
So while I agree that it would be nice to have unique (and non null) constraint violations wrapped in a Bean Validation exception, this is currently not the case.
References
Bean Validation specification (JSR 303)
Appendix D. Java Persistence 2.0 integration
Question about validation and persistence constraints
More information on how to implement a #Unique and the problematic around it can be found here - http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator
Well you CAN do it, but it's not trivial. The problem is: the validator requires database access to perform some queries to check, if the value you want to insert is already there or not. And this can't be really done from the validator, as it doesn't have access to the sessionFactory/session. Of course you could instantiate it (session/sessionFactory) inside the validator, but it's not a good coding practice.
You can make a validator read the JPA annotations and apply it. Here is somewhat of an example using spring validators that can be used as an idea to expand on.
JPA JSR303 Spring Form Validation
You can also inject (#Inject or Spring's #Autowired) your session bean in a custom validator and the container should know how to wire it up. I only know this as a Spring example:
import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
#Autowired //#Inject
private Foo aDependency;
...
}
You should try (insert or update), catch the exception and do some action. For example in a JSF backing bean :
try {
dao.create(record);//or dao.modify(record)
//add message success
} catch(EJBException e) {
//look for origin of error (duplicate label, duplicate code, ...)
var err = dao.isUnique(record);
if(err == null) throw e;//other error
String clientId = null;
String message = null;
switch(err) {
case CODE:
clientId = "client_id_of_input_code";
message = "duplicate code";
break;
case LABEL:
clientId = "client_id_of_input_label";
message = "duplicate label";
break;
default:
throw new AssertionError();//or something else
}
facesContext.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, message));
facesContext.validationFailed();
}
Another option is to check before the insertion/modification. This can be time consuming and doesn't prevent the error to happen in the end.

Categories

Resources