org.hibernate.cfg.beanvalidation.BeanValidationEventListener Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.cfg.beanvalidation;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.hibernate.EntityMode;
import org.hibernate.boot.internal.ClassLoaderAccessImpl;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger;
/**
* Event listener used to enable Bean Validation for insert/update/delete events.
*
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
//FIXME review exception model
public class BeanValidationEventListener
implements PreInsertEventListener, PreUpdateEventListener, PreDeleteEventListener {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
BeanValidationEventListener.class.getName()
);
private ValidatorFactory factory;
private ConcurrentHashMap> associationsPerEntityPersister =
new ConcurrentHashMap>();
private GroupsPerOperation groupsPerOperation;
boolean initialized;
/**
* Constructor used in an environment where validator factory is injected (JPA2).
*
* @param factory The {@code ValidatorFactory} to use to create {@code Validator} instance(s)
* @param settings Configured properties
*/
public BeanValidationEventListener(ValidatorFactory factory, Map settings, ClassLoaderService classLoaderService) {
init( factory, settings, classLoaderService );
}
public void initialize(Map settings, ClassLoaderService classLoaderService) {
if ( !initialized ) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
init( factory, settings, classLoaderService );
}
}
private void init(ValidatorFactory factory, Map settings, ClassLoaderService classLoaderService) {
this.factory = factory;
groupsPerOperation = GroupsPerOperation.from( settings, new ClassLoaderAccessImpl( classLoaderService ) );
initialized = true;
}
public boolean onPreInsert(PreInsertEvent event) {
validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
event.getSession().getFactory(), GroupsPerOperation.Operation.INSERT
);
return false;
}
public boolean onPreUpdate(PreUpdateEvent event) {
validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
event.getSession().getFactory(), GroupsPerOperation.Operation.UPDATE
);
return false;
}
public boolean onPreDelete(PreDeleteEvent event) {
validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
event.getSession().getFactory(), GroupsPerOperation.Operation.DELETE
);
return false;
}
private void validate(T object, EntityMode mode, EntityPersister persister,
SessionFactoryImplementor sessionFactory, GroupsPerOperation.Operation operation) {
if ( object == null || mode != EntityMode.POJO ) {
return;
}
TraversableResolver tr = new HibernateTraversableResolver(
persister, associationsPerEntityPersister, sessionFactory
);
Validator validator = factory.usingContext()
.traversableResolver( tr )
.getValidator();
final Class[] groups = groupsPerOperation.get( operation );
if ( groups.length > 0 ) {
final Set> constraintViolations = validator.validate( object, groups );
if ( constraintViolations.size() > 0 ) {
Set> propagatedViolations =
new HashSet>( constraintViolations.size() );
Set classNames = new HashSet();
for ( ConstraintViolation violation : constraintViolations ) {
LOG.trace( violation );
propagatedViolations.add( violation );
classNames.add( violation.getLeafBean().getClass().getName() );
}
StringBuilder builder = new StringBuilder();
builder.append( "Validation failed for classes " );
builder.append( classNames );
builder.append( " during " );
builder.append( operation.getName() );
builder.append( " time for groups " );
builder.append( toString( groups ) );
builder.append( "\nList of constraint violations:[\n" );
for (ConstraintViolation violation : constraintViolations) {
builder.append( "\t" ).append( violation.toString() ).append("\n");
}
builder.append( "]" );
throw new ConstraintViolationException(
builder.toString(), propagatedViolations
);
}
}
}
private String toString(Class[] groups) {
StringBuilder toString = new StringBuilder( "[" );
for ( Class group : groups ) {
toString.append( group.getName() ).append( ", " );
}
toString.append( "]" );
return toString.toString();
}
}