Configure JSR-303 hibernate validator with different mappings - java

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.

Related

hibernate how to bootstrap JPA EntityManager with customized configuration

I used to use hibernate native bootstrapping approaches, where I would like to add some customized things such as triggers, customized indexes etc.
Specifically, something like this:
Configuration configuration = new CustomConfiguration().configure()
.addAnnotatedClass(XXXXX.class)
...;
configuration.addAuxiliaryDatabaseObject(...); // add some customzied triggers and index here
// use this configure to create a hibernate native SessionFactory
Now our team is migrating to JPA standard APIs, so I'm wondering how should I do this with standard JPA's EntityManagerFactory?
The AuxiliaryDatabaseObject I used is a very hibernate-specific thing....so I guess the only way I do this is to get some hibernate delegate from EntityManagerFactory and do a hybrid bootstrapping....
Create a custom org.hibernate.boot.spi.MetadataContributor and register that as service through the Java service loader mechanism by adding a file META-INF/services/org.hibernate.boot.spi.MetadataContributor with the fully qualified name of your class as content.
This service will be picked up during boot automatically. In that class, you can add your auxiliary objects.

JSR 303 - How to get validator instance programmatically by annotation?

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.

How to use Integrator service in Hibernate 5 for adding annotated classes

This is with reference to JPA 2.0: Adding entity classes to PersistenceUnit *from different jar* automatically and Unable to call Hibernate/QueryDSL from another maven subproject
It seems that Hibernate 4 had a great way to dynamically load entity classes using
org.hibernate.integrator.spi.Integrator service.
Now when using Hibernate 5, the Integrator interface's integrate method gives me
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry)
{
}
Where metadata is of type org.hibernate.boot.Metadata
I am unable to call addAnnotatedClass(), neither I am able to obtain the original Configuration object that was there in Hibernate 4.
How do I get around with this?
I am using maven and jetty.
I am not using spring (so please do not provide any spring based solution)
This was actually related to something I was wrestling with over the weekend in getting caught up on Hibernate 5. You can read about the planned changes related to the Configuration class in the latest Javadoc for Hibernate 4. The new place for getting info on all loaded entity classes including annotated entities is the Metadata class you mentioned. It has a getEntityBindings() method that will return the PersistentClass entity metadata representation for known all entities. This Collection is immutable however.
Recommendation is that you rethink using an Integrator to add entity bindings at runtime. This may have worked in the past, but the docs clearly point towards that not being intentional as this should be done at the time of initialization. The Metadata and SessionFactoryImplementor are for the most part immutable once built, and so the Integrator's intended purpose is not to modify these configuration items but instead use them as information on how to configure new Service integrations using the SessionFactoryServiceRegistry.
And if you're finding it annoying to configure your Session to find all your annotated classes at runtime, I suggest you try using the EntityManagerFactory approach for initializing Hibernate as it is far more straightforward and uses standard JPA syntax that can be switched to a handful of other providers if you ever need to. This will automatically scan for annotated entities on your behalf. The API is a bit more simplified and limited, but if you really ever need the power of native Hibernate-specific functionality there is a way to access the native underlying API.

How to inject values from another properties file into ValidationMessages.properties?

I need to change the #NotNull message used by hibernate-validator.
Have successfully done this using a line in ValidationMessages.properties, e.g: javax.validation.constraints.NotNull.message=my validation message.
However, this isn't quite what's needed. Will spare the details about why but all these messages should originate from a single messages.properties file, whose purpose is not only for validation but other messages as well.
Let's say messages.properties initially contains a single property CCCI_0001=my generic message. Is it possible to somehow substitute this property value from messages.properties into a placeholder in ValidationMessages.properties?
What you can do is bootstrap your ValidatorFactory with a custom MessageInterpolator. If you are happy to use a Hibernate Validator specific feature, you can use a ResourceBundleLocator - see http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-custom-message-interpolation. It looks somewhat like this:
Validator validator = Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new PlatformResourceBundleLocator( "MyMessages" )
)
)
.buildValidatorFactory()
.getValidator();

Hibernate Validator 4 standalone: class constraints caching

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.

Categories

Resources