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.
Related
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.
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.
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'm developing an application, and I started with creating my JPA entities (annotation + persistence.xml). Then in my persistence.xml file, I created a connection for a MySql data base (the connection is fine).
The problem is that I just don't know how to persist my entities without creating a "main class".
Do I have to run my main class for every single entity that I'm going to create?
To persist an entity, you need an instance of entityManager. Since you have a Java EE container you can get an instance of entityManager using the annotation #PersistenceContext in some bean
What I mean by some bean ? It's a bean managed by the Java EE container. So, for instance you have to define a bean like this :
#Stateless
public class MyController{
#PersistenceContext
private EntityManager em;
public void persistIt(Object anEntity){
em.persist(anEntity);
}
}
The annotation #Stateless indicate to the container that it must manage this class and take care of providing an instance of the entityManager when needed.
So to answer precisely to your question: it is not mandatory to have another class to persist an entity, as soon as you find a way to get access to an entityManager instance.
But:
it is definitively NOT a best practice.
to take advantages of entityManager injection: you must use another managed bean so that entityManager can be injected by the container.
Additionally, the controller is where you can handle your transactions properly.
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.