JSR303 Hibernate dynamic validator - java

I'm new to hibernate validator
I would like to have one annotation and many implementations. Problem is, that annotation should be placed in domain (api) module and implementations in corresponding implementation modules (xx-command, xx-query). So the parameter validatedBy of #Constraint annotation has to be empty.
Can I somehow dynamically tell to hibernate to use all implementations of specified annotation which can pass type which I need. Also I would like to have implementations in more than one submodule.
#Target({FIELD, PARAMETER})
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {})
public #interface CanNotExists {
String message() default "com.foo.api.domain.validation.annotation.CanNotExists.message";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
this is my project structure (in dependency order accessor-command depends on accessor-query, accessor-query dependes on infrastrucutre ...)
-api
-infrastructure
-accessor-query
-accessor-command
I found this question and wanted to use xml configuration (see the edit section in answer), but it's not helpful because I would like to use implementation in many modules >>> as mentioned here
A given entity can only be configured once across all configuration files. The same applies for constraint definitions for a given constraint annotation. It can only occur in one mapping file. If these rules are violated a ValidationException is thrown.
So I can't split constraints to multiple xml configurations.
Basic need of this validator is to look into repository and validate if specified object already exists. I'm also using spring in my project so if somebody have better approach how to do this (even with spring or another framework), it will be welcome.
Thanks

Your question is tagged with 'spring', so may be you can use springs validation that under the hood uses hibernate :
[spring validation][1]
Let your validator implement the interface spring Validator, create a bean of it, thats it.

Related

How to implement custom class level Constraint Validation without Annotation?

I use the javax.validation and have a Hibernate validator on a classpath.
I would like to validate entities of a specific class on the class level (not fields level).
I can do this with by creating a custom class-level annotation and a paired ConstraintValidator as shown below:
#Constraint(validatedBy = CustomValidator.class)
#Target({ ElementType.TYPE })
public #interface CustomConstraintAnnotation {
}
class CustomValidator
implements ConstraintValidator<CustomConstraintAnnotation, Object> {
}
However, I would like to avoid creating a custom annotation and assign a custom validator per entity type, so that the validator would be registered for this type and validate instances of this type by default when validator.validate(entity) is invoked without having to annotate the type.
The javax.validation.ConstraintValidator does not fit, because it works only in pair with an annotation.
Basically, I would like to create a mapping between the type and the corresponding custom validator without using an annotation.
Is there a way to achieve this?

Spring validation: method parameter constraint not called

everyone.
So, I have a SpringBoot application with a controller that has several methods, taking the following POJO as a parameter:
package com.example.dto;
import lombok.Data;
#Data
public class MyEntity {
#NotNull
private String fieldA;
private String fieldB;
}
For one of the controller endpoints I would like to apply additional validation logic, so in the validation.xml I add the following:
<constraint-mappings>
<bean class="com.example.controller.SampleController" ignore-annotations="false">
<method name="doFoo">
<parameter type="com.example.dto.MyEntity">
<valid />
<constraint annotation="com.example.validation.ValidEntity" />
</parameter>
</method>
</bean>
</constraint-mappings>
com.example.validation.ValidEntity is the constraint annotation I would like to apply.
My problem is that this additional constraint is only invoked if #NotNull checks defined in MyEntity have passed successfully. If fieldA is null, ValidEntity constraint is ignored, and the client receives an imcomplete validation result. What am I missing?
I'm not entirely sure about this because I've never worked with the validation.xml file.
However, I would say that Spring is first creating the object and then applying the validations. The #NotNull validation is performed in the creation of the instance. This means that if that validation fails the construction will throw an exception and Spring won't even try to check your constraint (which makes sense in my opinion).
I think you can "fix" it by creating an annotation with your constraint and using it in your class. If I'm right, both annotations will be checked and the thrown exception will contain all errors.
It's just a guess. Let me know if it works.
I don't know if there is an easy way to configure the validator to aggregate constraint violations from both annotation and XML configurations when first or both fails.
As demonstrated by your code Hibernate Validator can work with mixed annotation and XML configurations, but the lack of documentation for that specific case is a hint that it is at least not recommended.
When XML configuration file is used, it takes precedence over annotations by default. ignore-annotations is used to overcome this (text highlight is mine):
Setting ignore-annotations to true means that constraint
annotations placed on the configured bean are ignored. The default for
this value is true. ignore-annotations is also available for the nodes
class, fields, getter, constructor, method, parameter, cross-parameter
and return-value. If not explicitly specified on these levels the
configured bean value applies.
Using Hibernate Validator to Cover Your Validation Needs article states that:
The default for a field is ignore-annotations=”false”. This means
that by default annotations for a field are stronger (this is of
course after you indicated that that the bean itself wont ignore
annotations). If you wont that the XML will be stronger than you have
to indicate that by ignore-annotations=”true”
It seems possible to disable annotation configuration for a specific field which is configured in XML.
Another solution to switch between annotation and XML configuration is to use Grouping constraints.
I'm not sure if anything of the above is of any use for you, but if it is possible I would probably switch to a single configuration (XML, assuming that annotation config comes from external library you cannot modify) and enforce it everywhere instead of relying on undocumented features.

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.

Is there a way to add a global annotation for all domains?

I want the annotation below to be the default for all of my domain objects.
#JsonInclude(Include.NON_NULL)
Rather than adding this manually to every domain class, I was wondering if there is a way to make this the default for all domains.
I am working with spring-boot application that utilizes Gradle for builds and JPA and Hibernate for persistence.
Java supports way to inherit annotation of super type if the annotation applied to super type is annotated with a meta annotation #Inherited doc.
But since the #JsonInclude annotation is not annotated with #Inherited, I think you'll have to add it manually to your domain classes.
You can make one SuperClass annotate the same with #JsonInclude(Include.NON_NULL) and extend it, like below:
#JsonInclude(Include.NON_NULL)
public class SuperClass {
}
public class SubClass extends SuperClass{
}

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