I could not find a way to apply a constraint conditionally, so I would like to make a validator that applies other annotations conditionally. I would like to be able to do:
#IfNotNull(validateWith = Email.class)
Then in my validator class, get the annotation classes from validateWith, get their validator instances, and validate via those if this value is not null. Unfortunately, I don't see a way to lookup a Validator instance by annotation.
Is there a way to do that or apply a constraint conditionally?
I am using Hibernate as the validation provider.
Related
I'm using EclipseLink 2.5 with JPA 2.1 in standalone java application.
Some field are marked with #Basic(optional=false), but even with null value I didn't get any error before commit. The constraint is set on database so I got a JDBC exception.
Adding Hibernate Validator to project and setting validation mode to callback didn't help.
Only with #NotNull annotation on field I got exception: javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details. which is not very specific and does not inform where the problem is.
I would like to know if there is any way to make this message look more robust: like field name not set or something like this and force eclipselink to check optional=false.
EDIT:
I know the difference between JPA and Bean Validation. I am trying to perform validation with JPA only, using optional=false. As far as I know (#Basic(optional = false) vs #Column(nullable = false) in JPA) #Basic(optional=false) should be checked at runtime and #Column(nullable=false) should be used to make column nonnullable in the database.
I'm looking for a method to display violations with out catching ConstraintViolations everywhere.
A couple of things here. First of you have to distinguish between JPA and Bean Validation. Two different specifications and things. #Basic is a JPA annotation whereas #NotNull is a Bean Validation annotation. Using #Basic(optional=false) in conjunction with schema creation you will indeed get a database constraint which in turn lead to a JDBC exception during persist.
By introducing Bean Validation you activate the JPA integration of Bean Validation. In this case prior to writing to the database the data will be validated via Bean Validation. In this case as part of pre-persist. As per specification a ConstraintViolationException is thrown in this case. You can call ConstraintViolationException.getConstraintViolations to get a set of the failing constraints. It is up to you to catch this exception and do the unwrapping yourself.
I'm looking for a method to display violations with out catching ConstraintViolations everywhere.
You could add a catch(ConstraintViolationException cve) {...} block at the outermost level of your application code (e.g. in form of some request handler/interceptor in case this is a web application) and use that to handle constraint violations in a generic way. The ConstraintViolation object provides lots of information such as the name of the concerned property etc. I'm not sure though why EclipseLink doesn't consider #Basic(optional=false), though.
I want to use Hibernate Validator 4 as a standalone package (i.e. without
Spring/Hibernate). The code which I found was the following (MyBean is some
bean with Hibernate Validator 4 annotations, myBean is its instance), and
it indeed returns the constraint violations:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<MyBean>> result = validator.validate(myBean);
However, I realized that the Validator instance does not seem to be per class;
if somebody knows: does Validator cache the constraints it got from processing myBean
(so that when I make the call again for the same class, e.g. validator.validate(myBean2),
it will not again search for annotations etc.)?
If so, perhaps one also knows where exactly these constraints get cached?
As you say Hibernate Validator caches the metadata. Here is the class responsible - https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java
Note, that there is no API to interact with the cache. The cache is cleared after memory demand.
I'm trying to set an attribute in an annotation, using Spring #Value, but I get Type mismatch: cannot convert from Value to String. Here is what I tried:
#Table(name = "myTable", catalog = #Value("${database.myCatalog}") )
Is it possible? And if yes, how to do it?
I think you are a little bit confused with how Spring uses that annotation.
As far as I know, the only way that annotation can only be set at field or method/constructor parameters.
Also, for Spring to resolve it, the POJO must be a Spring managed bean. That means that it must be defined in the Spring (Web)ApplicationContext implementation to be resolved.
Your question seems like you are annotating a JPA Entity which is not a Spring bean but a Class to be used by the JPA implementation that you are using (e.g. Hibernate).
I'm looking into using JSR-303 with hibernate validator. We would like to be able to have different validations per each customer or have a base set of constraints and allow them to be overridden.
I'm not sure what's the best way to do this.
Using annotations for constraints is not suitable since they're essentially hard-coded in the models. I know I can use XML to externalize the validations (creating META-INF/validation.xml which specifies constraint-mapping files). But I'm not really sure how to easily make this configurable for multiple customers.
I suppose I would like to be able to set a simple property so that when we deploy it uses a completely different set of constraint-mapping files.
Any ideas?
You could create a ValidatorFactory per customer which you configure with customer-specific constraint mapping XML files like this:
ValidatorFactory validatorFactory = Validation
.byDefaultProvider()
.configure()
.addMapping(...) //input stream with an XML constraint mapping
.addMapping(...) //another input stream with an XML constraint mapping
.buildValidatorFactory();
When you're working with Hibernate Validator, you could also use the API for programmatic constraint declaration to create individually configured validator factories.
I've been looking a around for a while now with no luck. I'n not using Spring MVC but still want to use #javax.validation.Valid to enable validation of method arguments. To give an example
public class EventServiceImpl implements IEventService {
#Override
public void invite(#Valid Event event, #Valid User user) { ... }
}
Using MVC, this is enabled for #Controller annotated beans with a simple <mvc:annotation-driven/> (see 5.7.4.3 Configuring a JSR-303 Validator for use by Spring MVC).
Using AOP should be quite trivial. Nevertheless, I suspect there's some standard way to do this. Hence the question: Is there a similar thing for non-MVC applications and non-controller beans to enable input validation for annotated beans?
Method level validation is not part of the Bean Validation specification (JSR 303). Method level validation is a suggestion in the spec added in appendix C.
Hibernate Validator 4.2 (a beta is out already) is implementing this suggestion and allows to place JSR 303 annotations on method parameters and return values. Of course you will still need some Spring glue code, but that should not be too hard.
Also Bean Validation 1.1 will add method level validation officially to the spec (not just as appendix/recommendation). See also http://beanvalidation.org/
Using MVC, this is enabled for #Controller annotated beans
#Valid is just a marker in Controller beans that hides the code that does the validation and puts all constraint violations in Errors in a nice way. Spring designers could have invented their own annotation to do the same thing.
The real use of #Valid annotation is in the class (bean) that you are validating with JSR 303 validator and its primary use is to validate the object graph. Meaning one bean can have other
bean references with #Valid annotation to trigger validation recursively.
Outside the MVC, you can use configured validator to validate any bean that uses JSR 303 annotations but, unlike the nicely populated Errors in controller, you will have to decide yourself what you are going to do with constraint violations.
So, to answer your question, there is no standard way. To have the same appearance as in a controller, you could use #Valid annotation (or create a new one) to run AOP advice to validate a bean and populate a 'ViolationCollector' (something like Errors in MVC) that must be passed to a method.
The answers seem to be quite old. As of now, you can utilize #Validated and MethodValidationPostProcessor for method inline validation of any Spring beans. They are basically responsible for creating pointcut-like behavior for Spring managed beans of any tier, not Controllers specifically.
Also see my other answer.