HHH-7990 - Bootstrapping Hibernate fails if javax.validation API is on classpath but no provider
(cherry picked from commit 898bab28ca
)
This commit is contained in:
parent
5a0a511142
commit
3bb451b10b
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.cfg.beanvalidation;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the context needed to call the {@link TypeSafeActivator}
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ActivationContext {
|
||||||
|
/**
|
||||||
|
* Access the requested validation mode(s).
|
||||||
|
* <p/>
|
||||||
|
* IMPL NOTE : the legacy code allowed multiple mode values to be specified, so that is why it is multi-valued here.
|
||||||
|
* However, I cannot find any good reasoning why it was defined that way and even JPA states it should be a single
|
||||||
|
* value. For 4.1 (in maintenance) I think it makes the most sense to not mess with it. Discuss for
|
||||||
|
* 4.2 and beyond.
|
||||||
|
*
|
||||||
|
* @return The requested validation modes
|
||||||
|
*/
|
||||||
|
public Set<ValidationMode> getValidationModes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access the Configuration
|
||||||
|
*
|
||||||
|
* @return The Hibernate Configuration object
|
||||||
|
*/
|
||||||
|
public Configuration getConfiguration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access the SessionFactory being built to trigger this BV activation
|
||||||
|
*
|
||||||
|
* @return The SessionFactory being built
|
||||||
|
*/
|
||||||
|
public SessionFactoryImplementor getSessionFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access the ServiceRegistry specific to the SessionFactory being built.
|
||||||
|
*
|
||||||
|
* @return The SessionFactoryServiceRegistry
|
||||||
|
*/
|
||||||
|
public SessionFactoryServiceRegistry getServiceRegistry();
|
||||||
|
}
|
|
@ -25,23 +25,15 @@ package org.hibernate.cfg.beanvalidation;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
|
||||||
import org.hibernate.integrator.spi.Integrator;
|
import org.hibernate.integrator.spi.Integrator;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
|
||||||
import org.hibernate.metamodel.source.MetadataImplementor;
|
import org.hibernate.metamodel.source.MetadataImplementor;
|
||||||
import org.hibernate.service.classloading.spi.ClassLoaderService;
|
import org.hibernate.service.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
|
@ -50,7 +42,10 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class BeanValidationIntegrator implements Integrator {
|
public class BeanValidationIntegrator implements Integrator {
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, BeanValidationIntegrator.class.getName());
|
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||||
|
CoreMessageLogger.class,
|
||||||
|
BeanValidationIntegrator.class.getName()
|
||||||
|
);
|
||||||
|
|
||||||
public static final String APPLY_CONSTRAINTS = "hibernate.validator.apply_to_ddl";
|
public static final String APPLY_CONSTRAINTS = "hibernate.validator.apply_to_ddl";
|
||||||
|
|
||||||
|
@ -58,16 +53,22 @@ public class BeanValidationIntegrator implements Integrator {
|
||||||
|
|
||||||
public static final String MODE_PROPERTY = "javax.persistence.validation.mode";
|
public static final String MODE_PROPERTY = "javax.persistence.validation.mode";
|
||||||
|
|
||||||
private static final String ACTIVATOR_CLASS = "org.hibernate.cfg.beanvalidation.TypeSafeActivator";
|
private static final String ACTIVATOR_CLASS_NAME = "org.hibernate.cfg.beanvalidation.TypeSafeActivator";
|
||||||
private static final String DDL_METHOD = "applyDDL";
|
private static final String VALIDATE_SUPPLIED_FACTORY_METHOD_NAME = "validateSuppliedFactory";
|
||||||
private static final String ACTIVATE_METHOD = "activateBeanValidation";
|
private static final String ACTIVATE_METHOD_NAME = "activate";
|
||||||
private static final String VALIDATE_METHOD = "validateFactory";
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate the type of an explicitly passed ValidatorFactory instance
|
||||||
|
*
|
||||||
|
* @param object The supposed ValidatorFactory instance
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static void validateFactory(Object object) {
|
public static void validateFactory(Object object) {
|
||||||
try {
|
try {
|
||||||
final Class activatorClass = BeanValidationIntegrator.class.getClassLoader().loadClass( ACTIVATOR_CLASS );
|
// this direct usage of ClassLoader should be fine since the classes exist in the same jar
|
||||||
|
final Class activatorClass = BeanValidationIntegrator.class.getClassLoader().loadClass( ACTIVATOR_CLASS_NAME );
|
||||||
try {
|
try {
|
||||||
final Method validateMethod = activatorClass.getMethod( VALIDATE_METHOD, Object.class );
|
final Method validateMethod = activatorClass.getMethod( VALIDATE_SUPPLIED_FACTORY_METHOD_NAME, Object.class );
|
||||||
if ( ! validateMethod.isAccessible() ) {
|
if ( ! validateMethod.isAccessible() ) {
|
||||||
validateMethod.setAccessible( true );
|
validateMethod.setAccessible( true );
|
||||||
}
|
}
|
||||||
|
@ -101,291 +102,114 @@ public class BeanValidationIntegrator implements Integrator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void integrate(
|
public void integrate(
|
||||||
Configuration configuration,
|
final Configuration configuration,
|
||||||
SessionFactoryImplementor sessionFactory,
|
final SessionFactoryImplementor sessionFactory,
|
||||||
SessionFactoryServiceRegistry serviceRegistry) {
|
final SessionFactoryServiceRegistry serviceRegistry) {
|
||||||
// determine requested validation modes.
|
// IMPL NOTE : see the comments on ActivationContext.getValidationModes() as to why this is multi-valued...
|
||||||
final Set<ValidationMode> modes = ValidationMode.getModes( configuration.getProperties().get( MODE_PROPERTY ) );
|
final Set<ValidationMode> modes = ValidationMode.getModes( configuration.getProperties().get( MODE_PROPERTY ) );
|
||||||
|
if ( modes.size() > 1 ) {
|
||||||
|
LOG.multipleValidationModes( ValidationMode.loggable( modes ) );
|
||||||
|
}
|
||||||
|
if ( modes.size() == 1 && modes.contains( ValidationMode.NONE ) ) {
|
||||||
|
// we have nothing to do; just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||||
Dialect dialect = serviceRegistry.getService( JdbcServices.class ).getDialect();
|
|
||||||
// try to locate a BV class to see if it is available on the classpath
|
// see if the Bean Validation API is available on the classpath
|
||||||
boolean isBeanValidationAvailable;
|
if ( isBeanValidationApiAvailable( classLoaderService ) ) {
|
||||||
|
// and if so, call out to the TypeSafeActivator
|
||||||
try {
|
try {
|
||||||
classLoaderService.classForName( BV_CHECK_CLASS );
|
final Class typeSafeActivatorClass = loadTypeSafeActivatorClass( classLoaderService );
|
||||||
isBeanValidationAvailable = true;
|
@SuppressWarnings("unchecked")
|
||||||
}
|
final Method activateMethod = typeSafeActivatorClass.getMethod( ACTIVATE_METHOD_NAME, ActivationContext.class );
|
||||||
catch ( Exception e ) {
|
final ActivationContext activationContext = new ActivationContext() {
|
||||||
isBeanValidationAvailable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// locate the type safe activator class
|
|
||||||
final Class typeSafeActivatorClass = loadTypeSafeActivatorClass( serviceRegistry );
|
|
||||||
|
|
||||||
// todo : if this works out, probably better to simply alter TypeSafeActivator into a single method...
|
|
||||||
applyRelationalConstraints(
|
|
||||||
modes,
|
|
||||||
isBeanValidationAvailable,
|
|
||||||
typeSafeActivatorClass,
|
|
||||||
configuration,
|
|
||||||
dialect
|
|
||||||
|
|
||||||
);
|
|
||||||
applyHibernateListeners(
|
|
||||||
modes,
|
|
||||||
isBeanValidationAvailable,
|
|
||||||
typeSafeActivatorClass,
|
|
||||||
configuration,
|
|
||||||
sessionFactory,
|
|
||||||
serviceRegistry
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void integrate( MetadataImplementor metadata,
|
public Set<ValidationMode> getValidationModes() {
|
||||||
SessionFactoryImplementor sessionFactory,
|
|
||||||
SessionFactoryServiceRegistry serviceRegistry ) {
|
|
||||||
// Properties props = sessionFactory.getProperties();
|
|
||||||
// final Set<ValidationMode> modes = ValidationMode.getModes(props.get(MODE_PROPERTY));
|
|
||||||
// final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
|
||||||
// // try to locate a BV class to see if it is available on the classpath
|
|
||||||
// boolean isBeanValidationAvailable;
|
|
||||||
// try {
|
|
||||||
// classLoaderService.classForName( BV_CHECK_CLASS );
|
|
||||||
// isBeanValidationAvailable = true;
|
|
||||||
// } catch (Exception error) {
|
|
||||||
// isBeanValidationAvailable = false;
|
|
||||||
// }
|
|
||||||
// // locate the type safe activator class
|
|
||||||
// final Class typeSafeActivatorClass = loadTypeSafeActivatorClass(serviceRegistry);
|
|
||||||
// // todo : if this works out, probably better to simply alter TypeSafeActivator into a single method...
|
|
||||||
// applyRelationalConstraints(modes, isBeanValidationAvailable, typeSafeActivatorClass, props, metadata);
|
|
||||||
// applyHibernateListeners(modes, isBeanValidationAvailable, typeSafeActivatorClass, sessionFactory, serviceRegistry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class loadTypeSafeActivatorClass(SessionFactoryServiceRegistry serviceRegistry) {
|
|
||||||
try {
|
|
||||||
return serviceRegistry.getService( ClassLoaderService.class ).classForName( ACTIVATOR_CLASS );
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyRelationalConstraints(
|
|
||||||
Set<ValidationMode> modes,
|
|
||||||
boolean beanValidationAvailable,
|
|
||||||
Class typeSafeActivatorClass,
|
|
||||||
Configuration configuration,
|
|
||||||
Dialect dialect) {
|
|
||||||
if ( ! ConfigurationHelper.getBoolean( APPLY_CONSTRAINTS, configuration.getProperties(), true ) ){
|
|
||||||
LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! ( modes.contains( ValidationMode.DDL ) || modes.contains( ValidationMode.AUTO ) ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! beanValidationAvailable ) {
|
|
||||||
if ( modes.contains( ValidationMode.DDL ) ) {
|
|
||||||
throw new HibernateException( "Bean Validation not available in the class path but required in " + MODE_PROPERTY );
|
|
||||||
}
|
|
||||||
else if (modes.contains( ValidationMode.AUTO ) ) {
|
|
||||||
//nothing to activate
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Method applyDDLMethod = typeSafeActivatorClass.getMethod( DDL_METHOD, Collection.class, Properties.class, Dialect.class );
|
|
||||||
try {
|
|
||||||
applyDDLMethod.invoke(
|
|
||||||
null,
|
|
||||||
configuration.createMappings().getClasses().values(),
|
|
||||||
configuration.getProperties(),
|
|
||||||
dialect
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (HibernateException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new HibernateException( "Error applying BeanValidation relational constraints", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HibernateException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private void applyRelationalConstraints( Set<ValidationMode> modes,
|
|
||||||
// boolean beanValidationAvailable,
|
|
||||||
// Class typeSafeActivatorClass,
|
|
||||||
// Properties properties,
|
|
||||||
// MetadataImplementor metadata ) {
|
|
||||||
// if (!ConfigurationHelper.getBoolean(APPLY_CONSTRAINTS, properties, true)){
|
|
||||||
// LOG.debug("Skipping application of relational constraints from legacy Hibernate Validator");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (!(modes.contains(ValidationMode.DDL) || modes.contains(ValidationMode.AUTO))) return;
|
|
||||||
// if (!beanValidationAvailable) {
|
|
||||||
// if (modes.contains(ValidationMode.DDL))
|
|
||||||
// throw new HibernateException("Bean Validation not available in the class path but required in " + MODE_PROPERTY);
|
|
||||||
// if(modes.contains(ValidationMode.AUTO)) return; //nothing to activate
|
|
||||||
// }
|
|
||||||
// try {
|
|
||||||
// Method applyDDLMethod = typeSafeActivatorClass.getMethod(DDL_METHOD, Iterable.class, Properties.class, ClassLoaderService.class);
|
|
||||||
// try {
|
|
||||||
// applyDDLMethod.invoke(null, metadata.getEntityBindings(), properties,
|
|
||||||
// metadata.getServiceRegistry().getService(ClassLoaderService.class));
|
|
||||||
// } catch (HibernateException error) {
|
|
||||||
// throw error;
|
|
||||||
// } catch (Exception error) {
|
|
||||||
// throw new HibernateException("Error applying BeanValidation relational constraints", error);
|
|
||||||
// }
|
|
||||||
// } catch (HibernateException error) {
|
|
||||||
// throw error;
|
|
||||||
// } catch (Exception error) {
|
|
||||||
// throw new HibernateException("Unable to locate TypeSafeActivator#applyDDL method", error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void applyHibernateListeners(
|
|
||||||
Set<ValidationMode> modes,
|
|
||||||
boolean beanValidationAvailable,
|
|
||||||
Class typeSafeActivatorClass,
|
|
||||||
Configuration configuration,
|
|
||||||
SessionFactoryImplementor sessionFactory,
|
|
||||||
SessionFactoryServiceRegistry serviceRegistry) {
|
|
||||||
// de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
|
|
||||||
// asks for it
|
|
||||||
if ( configuration.getProperty( Environment.CHECK_NULLABILITY ) == null ) {
|
|
||||||
sessionFactory.getSettings().setCheckNullability( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! ( modes.contains( ValidationMode.CALLBACK ) || modes.contains( ValidationMode.AUTO ) ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! beanValidationAvailable ) {
|
|
||||||
if ( modes.contains( ValidationMode.CALLBACK ) ) {
|
|
||||||
throw new HibernateException( "Bean Validation not available in the class path but required in " + MODE_PROPERTY );
|
|
||||||
}
|
|
||||||
else if (modes.contains( ValidationMode.AUTO ) ) {
|
|
||||||
//nothing to activate
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Method activateMethod = typeSafeActivatorClass.getMethod( ACTIVATE_METHOD, EventListenerRegistry.class, Configuration.class );
|
|
||||||
try {
|
|
||||||
activateMethod.invoke(
|
|
||||||
null,
|
|
||||||
serviceRegistry.getService( EventListenerRegistry.class ),
|
|
||||||
configuration
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (HibernateException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new HibernateException( "Error applying BeanValidation relational constraints", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HibernateException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private void applyHibernateListeners( Set<ValidationMode> modes,
|
|
||||||
// boolean beanValidationAvailable,
|
|
||||||
// Class typeSafeActivatorClass,
|
|
||||||
// SessionFactoryImplementor sessionFactory,
|
|
||||||
// SessionFactoryServiceRegistry serviceRegistry ) {
|
|
||||||
// // de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
|
|
||||||
// // asks for it
|
|
||||||
// if (sessionFactory.getProperties().getProperty(Environment.CHECK_NULLABILITY) == null)
|
|
||||||
// sessionFactory.getSettings().setCheckNullability( false );
|
|
||||||
// if (!(modes.contains( ValidationMode.CALLBACK) || modes.contains(ValidationMode.AUTO))) return;
|
|
||||||
// if (!beanValidationAvailable) {
|
|
||||||
// if (modes.contains(ValidationMode.CALLBACK))
|
|
||||||
// throw new HibernateException("Bean Validation not available in the class path but required in " + MODE_PROPERTY);
|
|
||||||
// if (modes.contains(ValidationMode.AUTO)) return; //nothing to activate
|
|
||||||
// }
|
|
||||||
// try {
|
|
||||||
// Method activateMethod = typeSafeActivatorClass.getMethod(ACTIVATE_METHOD, EventListenerRegistry.class);
|
|
||||||
// try {
|
|
||||||
// activateMethod.invoke(null, serviceRegistry.getService(EventListenerRegistry.class));
|
|
||||||
// }
|
|
||||||
// catch (HibernateException e) {
|
|
||||||
// throw e;
|
|
||||||
// }
|
|
||||||
// catch (Exception e) {
|
|
||||||
// throw new HibernateException( "Error applying BeanValidation relational constraints", e );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch (HibernateException e) {
|
|
||||||
// throw e;
|
|
||||||
// }
|
|
||||||
// catch (Exception e) {
|
|
||||||
// throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Because the javax validation classes might not be on the runtime classpath
|
|
||||||
private static enum ValidationMode {
|
|
||||||
AUTO,
|
|
||||||
CALLBACK,
|
|
||||||
NONE,
|
|
||||||
DDL;
|
|
||||||
|
|
||||||
public static Set<ValidationMode> getModes(Object modeProperty) {
|
|
||||||
Set<ValidationMode> modes = new HashSet<ValidationMode>(3);
|
|
||||||
if (modeProperty == null) {
|
|
||||||
modes.add(ValidationMode.AUTO);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final String[] modesInString = modeProperty.toString().split( "," );
|
|
||||||
for ( String modeInString : modesInString ) {
|
|
||||||
modes.add( getMode(modeInString) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( modes.size() > 1 && ( modes.contains( ValidationMode.AUTO ) || modes.contains( ValidationMode.NONE ) ) ) {
|
|
||||||
StringBuilder message = new StringBuilder( "Incompatible validation modes mixed: " );
|
|
||||||
for (ValidationMode mode : modes) {
|
|
||||||
message.append( mode ).append( ", " );
|
|
||||||
}
|
|
||||||
throw new HibernateException( message.substring( 0, message.length() - 2 ) );
|
|
||||||
}
|
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ValidationMode getMode(String modeProperty) {
|
@Override
|
||||||
if (modeProperty == null || modeProperty.length() == 0) {
|
public Configuration getConfiguration() {
|
||||||
return AUTO;
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryImplementor getSessionFactory() {
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryServiceRegistry getServiceRegistry() {
|
||||||
|
return serviceRegistry;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
activateMethod.invoke( null, activationContext );
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
if ( HibernateException.class.isInstance( e.getTargetException() ) ) {
|
||||||
|
throw ( (HibernateException) e.getTargetException() );
|
||||||
|
}
|
||||||
|
throw new IntegrationException( "Error activating Bean Validation integration", e.getTargetException() );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new IntegrationException( "Error activating Bean Validation integration", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new HibernateException( "Unable to locate TypeSafeActivator#activate method", e );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// otherwise check the validation modes
|
||||||
|
// todo : in many ways this duplicates thew checks done on the TypeSafeActivator when a ValidatorFactory could not be obtained
|
||||||
|
validateMissingBeanValidationApi( modes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBeanValidationApiAvailable(ClassLoaderService classLoaderService) {
|
||||||
try {
|
try {
|
||||||
return valueOf( modeProperty.trim().toUpperCase() );
|
classLoaderService.classForName( BV_CHECK_CLASS );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch ( IllegalArgumentException e ) {
|
catch (Exception e) {
|
||||||
throw new HibernateException( "Unknown validation mode in " + MODE_PROPERTY + ": " + modeProperty );
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate the case when the Bean Validation API is not available.
|
||||||
|
*
|
||||||
|
* @param modes The requested validation modes.
|
||||||
|
*/
|
||||||
|
private void validateMissingBeanValidationApi(Set<ValidationMode> modes) {
|
||||||
|
if ( modes.contains( ValidationMode.CALLBACK ) ) {
|
||||||
|
throw new IntegrationException( "Bean Validation API was not available, but 'callback' validation was requested" );
|
||||||
}
|
}
|
||||||
|
if ( modes.contains( ValidationMode.DDL ) ) {
|
||||||
|
throw new IntegrationException( "Bean Validation API was not available, but 'ddl' validation was requested" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class loadTypeSafeActivatorClass(ClassLoaderService classLoaderService) {
|
||||||
|
try {
|
||||||
|
return classLoaderService.classForName( ACTIVATOR_CLASS_NAME );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new HibernateException( "Unable to load TypeSafeActivator class", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void integrate(
|
||||||
|
MetadataImplementor metadata,
|
||||||
|
SessionFactoryImplementor sessionFactory,
|
||||||
|
SessionFactoryServiceRegistry serviceRegistry ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.cfg.beanvalidation;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates a problem integrating Hibernate and the Bean Validation spec.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class IntegrationException extends HibernateException {
|
||||||
|
public IntegrationException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegrationException(String message, Throwable root) {
|
||||||
|
super( message, root );
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,15 +23,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.beanvalidation;
|
package org.hibernate.cfg.beanvalidation;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import javax.validation.Validation;
|
import javax.validation.Validation;
|
||||||
import javax.validation.ValidatorFactory;
|
import javax.validation.ValidatorFactory;
|
||||||
import javax.validation.constraints.Digits;
|
import javax.validation.constraints.Digits;
|
||||||
|
@ -42,19 +33,29 @@ import javax.validation.constraints.Size;
|
||||||
import javax.validation.metadata.BeanDescriptor;
|
import javax.validation.metadata.BeanDescriptor;
|
||||||
import javax.validation.metadata.ConstraintDescriptor;
|
import javax.validation.metadata.ConstraintDescriptor;
|
||||||
import javax.validation.metadata.PropertyDescriptor;
|
import javax.validation.metadata.PropertyDescriptor;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||||
import org.hibernate.event.spi.EventType;
|
import org.hibernate.event.spi.EventType;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
@ -64,6 +65,7 @@ import org.hibernate.mapping.SingleTableSubclass;
|
||||||
/**
|
/**
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
class TypeSafeActivator {
|
class TypeSafeActivator {
|
||||||
|
|
||||||
|
@ -71,51 +73,97 @@ class TypeSafeActivator {
|
||||||
|
|
||||||
private static final String FACTORY_PROPERTY = "javax.persistence.validation.factory";
|
private static final String FACTORY_PROPERTY = "javax.persistence.validation.factory";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate a supplied ValidatorFactory instance as being castable to ValidatorFactory.
|
||||||
|
*
|
||||||
|
* @param object The supplied ValidatorFactory instance.
|
||||||
|
*/
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public static void validateFactory(Object object) {
|
public static void validateSuppliedFactory(Object object) {
|
||||||
if ( ! ValidatorFactory.class.isInstance( object ) ) {
|
if ( ! ValidatorFactory.class.isInstance( object ) ) {
|
||||||
throw new HibernateException(
|
throw new IntegrationException(
|
||||||
"Given object was not an instance of " + ValidatorFactory.class.getName()
|
"Given object was not an instance of " + ValidatorFactory.class.getName()
|
||||||
+ "[" + object.getClass().getName() + "]"
|
+ "[" + object.getClass().getName() + "]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
public static void activate(ActivationContext activationContext) {
|
||||||
|
final Properties properties = activationContext.getConfiguration().getProperties();
|
||||||
|
final ValidatorFactory factory;
|
||||||
|
try {
|
||||||
|
factory = getValidatorFactory( properties );
|
||||||
|
}
|
||||||
|
catch (IntegrationException e) {
|
||||||
|
if ( activationContext.getValidationModes().contains( ValidationMode.CALLBACK ) ) {
|
||||||
|
throw new IntegrationException( "Bean Validation provider was not available, but 'callback' validation was requested", e );
|
||||||
|
}
|
||||||
|
if ( activationContext.getValidationModes().contains( ValidationMode.DDL ) ) {
|
||||||
|
throw new IntegrationException( "Bean Validation provider was not available, but 'ddl' validation was requested", e );
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug( "Unable to acquire Bean Validation ValidatorFactory, skipping activation" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyRelationalConstraints( factory, activationContext );
|
||||||
|
|
||||||
|
applyCallbackListeners( factory, activationContext );
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public static void activateBeanValidation(EventListenerRegistry listenerRegistry, Configuration configuration) {
|
public static void applyCallbackListeners(ValidatorFactory validatorFactory, ActivationContext activationContext) {
|
||||||
final Properties properties = configuration.getProperties();
|
final Set<ValidationMode> modes = activationContext.getValidationModes();
|
||||||
ValidatorFactory factory = getValidatorFactory( properties );
|
if ( ! ( modes.contains( ValidationMode.CALLBACK ) || modes.contains( ValidationMode.AUTO ) ) ) {
|
||||||
BeanValidationEventListener listener = new BeanValidationEventListener(
|
return;
|
||||||
factory, properties
|
}
|
||||||
|
|
||||||
|
// de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
|
||||||
|
// asks for it
|
||||||
|
if ( activationContext.getConfiguration().getProperty( Environment.CHECK_NULLABILITY ) == null ) {
|
||||||
|
activationContext.getSessionFactory().getSettings().setCheckNullability( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
final BeanValidationEventListener listener = new BeanValidationEventListener(
|
||||||
|
validatorFactory,
|
||||||
|
activationContext.getConfiguration().getProperties()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final EventListenerRegistry listenerRegistry = activationContext.getServiceRegistry()
|
||||||
|
.getService( EventListenerRegistry.class );
|
||||||
|
|
||||||
listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE );
|
listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE );
|
||||||
|
|
||||||
listenerRegistry.appendListeners( EventType.PRE_INSERT, listener );
|
listenerRegistry.appendListeners( EventType.PRE_INSERT, listener );
|
||||||
listenerRegistry.appendListeners( EventType.PRE_UPDATE, listener );
|
listenerRegistry.appendListeners( EventType.PRE_UPDATE, listener );
|
||||||
listenerRegistry.appendListeners( EventType.PRE_DELETE, listener );
|
listenerRegistry.appendListeners( EventType.PRE_DELETE, listener );
|
||||||
|
|
||||||
listener.initialize( configuration );
|
listener.initialize( activationContext.getConfiguration() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static void activateBeanValidation( EventListenerRegistry listenerRegistry ) {
|
@SuppressWarnings({"unchecked", "UnusedParameters"})
|
||||||
// final Properties properties = configuration.getProperties();
|
private static void applyRelationalConstraints(ValidatorFactory factory, ActivationContext activationContext) {
|
||||||
// ValidatorFactory factory = getValidatorFactory( properties );
|
final Properties properties = activationContext.getConfiguration().getProperties();
|
||||||
// BeanValidationEventListener listener = new BeanValidationEventListener(
|
if ( ! ConfigurationHelper.getBoolean( BeanValidationIntegrator.APPLY_CONSTRAINTS, properties, true ) ){
|
||||||
// factory, properties
|
LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
|
||||||
// );
|
return;
|
||||||
//
|
}
|
||||||
// listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE );
|
|
||||||
//
|
final Set<ValidationMode> modes = activationContext.getValidationModes();
|
||||||
// listenerRegistry.appendListeners( EventType.PRE_INSERT, listener );
|
if ( ! ( modes.contains( ValidationMode.DDL ) || modes.contains( ValidationMode.AUTO ) ) ) {
|
||||||
// listenerRegistry.appendListeners( EventType.PRE_UPDATE, listener );
|
return;
|
||||||
// listenerRegistry.appendListeners( EventType.PRE_DELETE, listener );
|
}
|
||||||
//
|
|
||||||
// listener.initialize( configuration );
|
applyRelationalConstraints(
|
||||||
// }
|
activationContext.getConfiguration().createMappings().getClasses().values(),
|
||||||
|
properties,
|
||||||
|
activationContext.getServiceRegistry().getService( JdbcServices.class ).getDialect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public static void applyDDL(Collection<PersistentClass> persistentClasses, Properties properties, Dialect dialect) {
|
public static void applyRelationalConstraints(Collection<PersistentClass> persistentClasses, Properties properties, Dialect dialect) {
|
||||||
ValidatorFactory factory = getValidatorFactory( properties );
|
ValidatorFactory factory = getValidatorFactory( properties );
|
||||||
Class<?>[] groupsArray = new GroupsPerOperation( properties ).get( GroupsPerOperation.Operation.DDL );
|
Class<?>[] groupsArray = new GroupsPerOperation( properties ).get( GroupsPerOperation.Operation.DDL );
|
||||||
Set<Class<?>> groups = new HashSet<Class<?>>( Arrays.asList( groupsArray ) );
|
Set<Class<?>> groups = new HashSet<Class<?>>( Arrays.asList( groupsArray ) );
|
||||||
|
@ -143,26 +191,8 @@ class TypeSafeActivator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static void applyDDL( Iterable<EntityBinding> bindings,
|
private static void applyDDL(
|
||||||
// Properties properties,
|
String prefix,
|
||||||
// ClassLoaderService classLoaderService ) {
|
|
||||||
// ValidatorFactory factory = getValidatorFactory(properties);
|
|
||||||
// Class<?>[] groupsArray = new GroupsPerOperation(properties).get(GroupsPerOperation.Operation.DDL);
|
|
||||||
// Set<Class<?>> groups = new HashSet<Class<?>>(Arrays.asList(groupsArray));
|
|
||||||
// for (EntityBinding binding : bindings) {
|
|
||||||
// final String className = binding.getEntity().getClassName();
|
|
||||||
// if (className == null || className.length() == 0) continue;
|
|
||||||
// try {
|
|
||||||
// applyDDL("", binding, classLoaderService.classForName(className), factory, groups, true);
|
|
||||||
// } catch (ClassLoadingException error) {
|
|
||||||
// throw new AssertionFailure("Entity class not found", error);
|
|
||||||
// } catch (Exception error) {
|
|
||||||
// LOG.unableToApplyConstraints(className, error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static void applyDDL(String prefix,
|
|
||||||
PersistentClass persistentClass,
|
PersistentClass persistentClass,
|
||||||
Class<?> clazz,
|
Class<?> clazz,
|
||||||
ValidatorFactory factory,
|
ValidatorFactory factory,
|
||||||
|
@ -200,30 +230,13 @@ class TypeSafeActivator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static void applyDDL( String prefix,
|
private static boolean applyConstraints(
|
||||||
// EntityBinding binding,
|
Set<ConstraintDescriptor<?>> constraintDescriptors,
|
||||||
// Class<?> clazz,
|
|
||||||
// ValidatorFactory factory,
|
|
||||||
// Set<Class<?>> groups,
|
|
||||||
// boolean activateNotNull ) {
|
|
||||||
// final BeanDescriptor descriptor = factory.getValidator().getConstraintsForClass(clazz);
|
|
||||||
// //no bean level constraints can be applied, go to the properties
|
|
||||||
// for (PropertyDescriptor propertyDesc : descriptor.getConstrainedProperties()) {
|
|
||||||
// AttributeBinding attrBinding = findAttributeBindingByName(binding, prefix + propertyDesc.getPropertyName());
|
|
||||||
// if (attrBinding != null) {
|
|
||||||
// applyConstraints(propertyDesc.getConstraintDescriptors(), attrBinding, propertyDesc, groups, activateNotNull);
|
|
||||||
// // TODO: Handle composite attributes when possible
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static boolean applyConstraints(Set<ConstraintDescriptor<?>> constraintDescriptors,
|
|
||||||
Property property,
|
Property property,
|
||||||
PropertyDescriptor propertyDesc,
|
PropertyDescriptor propertyDesc,
|
||||||
Set<Class<?>> groups,
|
Set<Class<?>> groups,
|
||||||
boolean canApplyNotNull,
|
boolean canApplyNotNull,
|
||||||
Dialect dialect
|
Dialect dialect) {
|
||||||
) {
|
|
||||||
boolean hasNotNull = false;
|
boolean hasNotNull = false;
|
||||||
for ( ConstraintDescriptor<?> descriptor : constraintDescriptors ) {
|
for ( ConstraintDescriptor<?> descriptor : constraintDescriptors ) {
|
||||||
if ( groups != null && Collections.disjoint( descriptor.getGroups(), groups ) ) {
|
if ( groups != null && Collections.disjoint( descriptor.getGroups(), groups ) ) {
|
||||||
|
@ -256,37 +269,6 @@ class TypeSafeActivator {
|
||||||
return hasNotNull;
|
return hasNotNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static boolean applyConstraints( Set<ConstraintDescriptor<?>> constraintDescriptors,
|
|
||||||
// AttributeBinding attributeBinding,
|
|
||||||
// PropertyDescriptor propertyDesc,
|
|
||||||
// Set<Class<?>> groups,
|
|
||||||
// boolean canApplyNotNull ) {
|
|
||||||
// boolean hasNotNull = false;
|
|
||||||
// for ( ConstraintDescriptor<?> descriptor : constraintDescriptors ) {
|
|
||||||
// if (groups != null && Collections.disjoint(descriptor.getGroups(), groups)) continue;
|
|
||||||
// if (canApplyNotNull) hasNotNull = hasNotNull || applyNotNull(attributeBinding, descriptor);
|
|
||||||
//
|
|
||||||
// // apply bean validation specific constraints
|
|
||||||
// applyDigits( property, descriptor );
|
|
||||||
// applySize( property, descriptor, propertyDesc );
|
|
||||||
// applyMin( property, descriptor );
|
|
||||||
// applyMax( property, descriptor );
|
|
||||||
//
|
|
||||||
// // apply hibernate validator specific constraints - we cannot import any HV specific classes though!
|
|
||||||
// // no need to check explicitly for @Range. @Range is a composed constraint using @Min and @Max which
|
|
||||||
// // will be taken care later
|
|
||||||
// applyLength( property, descriptor, propertyDesc );
|
|
||||||
//
|
|
||||||
// // pass an empty set as composing constraints inherit the main constraint and thus are matching already
|
|
||||||
// hasNotNull = hasNotNull || applyConstraints(
|
|
||||||
// descriptor.getComposingConstraints(),
|
|
||||||
// property, propertyDesc, null,
|
|
||||||
// canApplyNotNull
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return hasNotNull;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static void applyMin(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) {
|
private static void applyMin(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) {
|
||||||
if ( Min.class.equals( descriptor.getAnnotation().annotationType() ) ) {
|
if ( Min.class.equals( descriptor.getAnnotation().annotationType() ) ) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -339,26 +321,6 @@ class TypeSafeActivator {
|
||||||
return hasNotNull;
|
return hasNotNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static boolean applyNotNull( AttributeBinding attributeBinding,
|
|
||||||
// ConstraintDescriptor<?> descriptor ) {
|
|
||||||
// boolean hasNotNull = false;
|
|
||||||
// if (NotNull.class.equals(descriptor.getAnnotation().annotationType())) {
|
|
||||||
// if ( !( attributeBinding.getPersistentClass() instanceof SingleTableSubclass ) ) {
|
|
||||||
// //single table should not be forced to null
|
|
||||||
// if ( !property.isComposite() ) { //composite should not add not-null on all columns
|
|
||||||
// @SuppressWarnings( "unchecked" )
|
|
||||||
// Iterator<Column> iter = property.getColumnIterator();
|
|
||||||
// while ( iter.hasNext() ) {
|
|
||||||
// iter.next().setNullable( false );
|
|
||||||
// hasNotNull = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// hasNotNull = true;
|
|
||||||
// }
|
|
||||||
// return hasNotNull;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static void applyDigits(Property property, ConstraintDescriptor<?> descriptor) {
|
private static void applyDigits(Property property, ConstraintDescriptor<?> descriptor) {
|
||||||
if ( Digits.class.equals( descriptor.getAnnotation().annotationType() ) ) {
|
if ( Digits.class.equals( descriptor.getAnnotation().annotationType() ) ) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -462,44 +424,6 @@ class TypeSafeActivator {
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @param entityBinding
|
|
||||||
// * @param attrName
|
|
||||||
// * @return the attribute by path in a recursive way, including EntityIdentifier in the loop if attrName is
|
|
||||||
// * <code>null</code>. If attrName is <code>null</code> or empty, the EntityIdentifier is returned
|
|
||||||
// */
|
|
||||||
// private static AttributeBinding findAttributeBindingByName( EntityBinding entityBinding,
|
|
||||||
// String attrName ) {
|
|
||||||
// AttributeBinding attrBinding = null;
|
|
||||||
// EntityIdentifier identifier = entityBinding.getHierarchyDetails().getEntityIdentifier();
|
|
||||||
// BasicAttributeBinding idAttrBinding = identifier.getValueBinding();
|
|
||||||
// String idAttrName = idAttrBinding != null ? idAttrBinding.getAttribute().getName() : null;
|
|
||||||
// try {
|
|
||||||
// if (attrName == null || attrName.length() == 0 || attrName.equals(idAttrName)) attrBinding = idAttrBinding; // default to id
|
|
||||||
// else {
|
|
||||||
// if (attrName.indexOf(idAttrName + ".") == 0) {
|
|
||||||
// attrBinding = idAttrBinding;
|
|
||||||
// attrName = attrName.substring(idAttrName.length() + 1);
|
|
||||||
// }
|
|
||||||
// for (StringTokenizer st = new StringTokenizer(attrName, "."); st.hasMoreElements();) {
|
|
||||||
// String element = st.nextToken();
|
|
||||||
// if (attrBinding == null) attrBinding = entityBinding.locateAttributeBinding(element);
|
|
||||||
// else return null; // TODO: if (attrBinding.isComposite()) ...
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } catch (MappingException error) {
|
|
||||||
// try {
|
|
||||||
// //if we do not find it try to check the identifier mapper
|
|
||||||
// if (!identifier.isIdentifierMapper()) return null;
|
|
||||||
// // TODO: finish once composite/embedded/component IDs get worked out
|
|
||||||
// }
|
|
||||||
// catch ( MappingException ee ) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return attrBinding;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static ValidatorFactory getValidatorFactory(Map<Object, Object> properties) {
|
private static ValidatorFactory getValidatorFactory(Map<Object, Object> properties) {
|
||||||
ValidatorFactory factory = null;
|
ValidatorFactory factory = null;
|
||||||
if ( properties != null ) {
|
if ( properties != null ) {
|
||||||
|
@ -509,7 +433,7 @@ class TypeSafeActivator {
|
||||||
factory = ValidatorFactory.class.cast( unsafeProperty );
|
factory = ValidatorFactory.class.cast( unsafeProperty );
|
||||||
}
|
}
|
||||||
catch ( ClassCastException e ) {
|
catch ( ClassCastException e ) {
|
||||||
throw new HibernateException(
|
throw new IntegrationException(
|
||||||
"Property " + FACTORY_PROPERTY
|
"Property " + FACTORY_PROPERTY
|
||||||
+ " should contain an object of type " + ValidatorFactory.class.getName()
|
+ " should contain an object of type " + ValidatorFactory.class.getName()
|
||||||
);
|
);
|
||||||
|
@ -521,7 +445,7 @@ class TypeSafeActivator {
|
||||||
factory = Validation.buildDefaultValidatorFactory();
|
factory = Validation.buildDefaultValidatorFactory();
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
catch ( Exception e ) {
|
||||||
throw new HibernateException( "Unable to build the default ValidatorFactory", e );
|
throw new IntegrationException( "Unable to build the default ValidatorFactory", e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return factory;
|
return factory;
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.cfg.beanvalidation;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duplicates the javax.validation enum (because javax validation might not be on the runtime classpath)
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public enum ValidationMode {
|
||||||
|
AUTO( "auto" ),
|
||||||
|
CALLBACK( "callback" ),
|
||||||
|
NONE( "none" ),
|
||||||
|
DDL( "ddl" );
|
||||||
|
|
||||||
|
private final String externalForm;
|
||||||
|
|
||||||
|
private ValidationMode(String externalForm) {
|
||||||
|
this.externalForm = externalForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<ValidationMode> getModes(Object modeProperty) {
|
||||||
|
Set<ValidationMode> modes = new HashSet<ValidationMode>(3);
|
||||||
|
if (modeProperty == null) {
|
||||||
|
modes.add( ValidationMode.AUTO );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final String[] modesInString = modeProperty.toString().split( "," );
|
||||||
|
for ( String modeInString : modesInString ) {
|
||||||
|
modes.add( getMode(modeInString) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( modes.size() > 1 && ( modes.contains( ValidationMode.AUTO ) || modes.contains( ValidationMode.NONE ) ) ) {
|
||||||
|
throw new HibernateException( "Incompatible validation modes mixed: " + loggable( modes ) );
|
||||||
|
}
|
||||||
|
return modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ValidationMode getMode(String modeProperty) {
|
||||||
|
if (modeProperty == null || modeProperty.length() == 0) {
|
||||||
|
return AUTO;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
return valueOf( modeProperty.trim().toUpperCase() );
|
||||||
|
}
|
||||||
|
catch ( IllegalArgumentException e ) {
|
||||||
|
throw new HibernateException( "Unknown validation mode in " + BeanValidationIntegrator.MODE_PROPERTY + ": " + modeProperty );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String loggable(Set<ValidationMode> modes) {
|
||||||
|
if ( modes == null || modes.isEmpty() ) {
|
||||||
|
return "[<empty>]";
|
||||||
|
}
|
||||||
|
StringBuilder buffer = new StringBuilder( "[" );
|
||||||
|
String sep = "";
|
||||||
|
for ( ValidationMode mode : modes ) {
|
||||||
|
buffer.append( sep ).append( mode.externalForm );
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
return buffer.append( "]" ).toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1609,4 +1609,7 @@ public interface CoreMessageLogger extends BasicLogger {
|
||||||
)
|
)
|
||||||
void embedXmlAttributesNoLongerSupported();
|
void embedXmlAttributesNoLongerSupported();
|
||||||
|
|
||||||
|
@LogMessage(level = INFO)
|
||||||
|
@Message( value = "'javax.persistence.validation.mode' named multiple values : %s", id = 447 )
|
||||||
|
void multipleValidationModes(String modes);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue