I\'m a bit of a Java EE/EJB noob, but from the docs and other posts I\'ve gathered you cannot query the database using the same entitymanager/session during entity validatio
Through some of the comments and enough scrounging around, I finally figured out a somewhat 'canonical' way to answer my question.
But to clear things up, my question really was asking two things which have 2 distinct answers:
Answering the second question first I'll simply say, it is strongly encouraged to use a second EntityManager to do queries during validation. That means you should be injecting an EntityManagerFactory and creating a new EntityManager for queries (rather than injecting an EntityManager which will be the same one that created the lifecycle event to begin with).
Generally speaking, for validation purposes, you'll only be querying the database anyway and not inserting/updating so this should be fairly safe to do.
I asked a very related SO question here.
Now to answer question 1.
Yes it is completely possible to inject things into Validators used in the Hibernate Validation framework. To accomplish this you need to do 3 things:
Here is an example custom ConstraintValidatorFactory that uses 'managed' (injectable) validators:
package com.myvalidator;
public class ConstraintInjectableValidatorFactory implements ConstraintValidatorFactory {
private static BeanManager beanManager;
@SuppressWarnings(value="unchecked")
@Override
public > T getInstance(Class clazz) {
// lazily initialize the beanManager
if (beanManager == null) {
try {
beanManager = (BeanManager) InitialContext.doLookup("java:comp/BeanManager");
} catch (NamingException e) {
// TODO what's the best way to handle this?
throw new RuntimeException(e);
}
}
T result = null;
Bean bean = (Bean) beanManager.resolve(beanManager.getBeans(clazz));
// if the bean/validator specified by clazz is not null that means it has
// injection points so get it from the beanManager and return it. The validator
// that comes from the beanManager will already be injected.
if (bean != null) {
CreationalContext context = beanManager.createCreationalContext(bean);
if (context != null) {
result = (T) beanManager.getReference(bean, clazz, context);
}
// the bean/validator was not in the beanManager meaning it has no injection
// points so go ahead and just instantiate a new instance and return it
} else {
try {
result = clazz.newInstance();
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
return result;
}
}
Here is an example validation.xml file that tells Hibernate Validator which class to use as the ValidatorFactory:
com.myvalidator.ConstraintInjectableValidatorFactory
And finally a validator class with injection points:
public class UserValidator implements ConstraintValidator {
@PersistenceUnit(unitName="myvalidator")
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
@Override
public void initialize(ValidUser annotation) {
}
@Override
public boolean isValid(User user, ConstraintValidatorContext context) {
// validation takes place during the entityManager.persist() lifecycle, so
// here we create a new entityManager separate from the original one that
// invoked this validation
entityManager = entityManagerFactory.createEntityManager();
// use entityManager to query database for needed validation
entityManager.close();
}
}