minor cleanups in TypeSafeActivator

This commit is contained in:
Gavin King 2024-10-12 14:21:43 +02:00
parent 968a66186d
commit 7afb5a0c50
1 changed files with 198 additions and 188 deletions

View File

@ -6,16 +6,20 @@ package org.hibernate.boot.beanvalidation;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.boot.internal.ClassLoaderAccessImpl; import org.hibernate.boot.internal.ClassLoaderAccessImpl;
@ -47,12 +51,19 @@ import jakarta.validation.metadata.BeanDescriptor;
import jakarta.validation.metadata.ConstraintDescriptor; import jakarta.validation.metadata.ConstraintDescriptor;
import jakarta.validation.metadata.PropertyDescriptor; import jakarta.validation.metadata.PropertyDescriptor;
import static java.util.Arrays.asList;
import static java.util.Collections.disjoint;
import static org.hibernate.boot.beanvalidation.BeanValidationIntegrator.APPLY_CONSTRAINTS;
import static org.hibernate.boot.beanvalidation.GroupsPerOperation.buildGroupsForOperation; import static org.hibernate.boot.beanvalidation.GroupsPerOperation.buildGroupsForOperation;
import static org.hibernate.cfg.ValidationSettings.CHECK_NULLABILITY; import static org.hibernate.cfg.ValidationSettings.CHECK_NULLABILITY;
import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_FACTORY; import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_FACTORY;
import static org.hibernate.cfg.ValidationSettings.JPA_VALIDATION_FACTORY; import static org.hibernate.cfg.ValidationSettings.JPA_VALIDATION_FACTORY;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/** /**
* Sets up Bean Validation {@linkplain BeanValidationEventListener event listener} and DDL-based constraints.
*
* @author Emmanuel Bernard * @author Emmanuel Bernard
* @author Hardy Ferentschik * @author Hardy Ferentschik
* @author Steve Ebersole * @author Steve Ebersole
@ -69,88 +80,103 @@ class TypeSafeActivator {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static void validateSuppliedFactory(Object object) { public static void validateSuppliedFactory(Object object) {
if ( !(object instanceof ValidatorFactory) ) { if ( !(object instanceof ValidatorFactory) ) {
throw new IntegrationException( 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("unused") @SuppressWarnings("unused")
public static void activate(ActivationContext activationContext) { public static void activate(ActivationContext context) {
final ValidatorFactory factory; final ValidatorFactory factory;
try { try {
factory = getValidatorFactory( activationContext ); factory = getValidatorFactory( context );
} }
catch (IntegrationException e) { catch (IntegrationException e) {
if ( activationContext.getValidationModes().contains( ValidationMode.CALLBACK ) ) { final Set<ValidationMode> validationModes = context.getValidationModes();
if ( validationModes.contains( ValidationMode.CALLBACK ) ) {
throw new IntegrationException( "Bean Validation provider was not available, but 'callback' validation was requested", e ); throw new IntegrationException( "Bean Validation provider was not available, but 'callback' validation was requested", e );
} }
if ( activationContext.getValidationModes().contains( ValidationMode.DDL ) ) { else if ( validationModes.contains( ValidationMode.DDL ) ) {
throw new IntegrationException( "Bean Validation provider was not available, but 'ddl' validation was requested", e ); throw new IntegrationException( "Bean Validation provider was not available, but 'ddl' validation was requested", e );
} }
else {
LOG.debug( "Unable to acquire Bean Validation ValidatorFactory, skipping activation" ); LOG.debug( "Unable to acquire Bean Validation ValidatorFactory, skipping activation" );
return; return;
} }
applyRelationalConstraints( factory, activationContext );
applyCallbackListeners( factory, activationContext );
} }
public static void applyCallbackListeners(ValidatorFactory validatorFactory, ActivationContext activationContext) { applyRelationalConstraints( factory, context );
final Set<ValidationMode> modes = activationContext.getValidationModes(); applyCallbackListeners( factory, context );
if ( !modes.contains( ValidationMode.CALLBACK ) && !modes.contains( ValidationMode.AUTO ) ) {
return;
} }
final SessionFactoryServiceRegistry serviceRegistry = activationContext.getServiceRegistry(); public static void applyCallbackListeners(ValidatorFactory validatorFactory, ActivationContext context) {
final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class ); if ( isValidationEnabled( context ) ) {
disableNullabilityChecking( context );
setupListener( validatorFactory, context.getServiceRegistry() );
}
}
private static boolean isValidationEnabled(ActivationContext context) {
final Set<ValidationMode> modes = context.getValidationModes();
return modes.contains( ValidationMode.CALLBACK )
|| modes.contains( ValidationMode.AUTO );
}
/**
* Deactivate not-null tracking at the core level when Bean Validation
* is present, unless the user explicitly asks for it.
*/
private static void disableNullabilityChecking(ActivationContext context) {
if ( isCheckNullabilityExplicit( context ) ) {
// no explicit setting, so disable null checking
context.getSessionFactory().getSessionFactoryOptions().setCheckNullability( false );
}
}
private static boolean isCheckNullabilityExplicit(ActivationContext context) {
return context.getServiceRegistry().requireService( ConfigurationService.class )
.getSettings().get( CHECK_NULLABILITY ) == null;
}
private static void setupListener(ValidatorFactory validatorFactory, SessionFactoryServiceRegistry serviceRegistry) {
final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class ); final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
final EventListenerRegistry listenerRegistry = serviceRegistry.requireService( EventListenerRegistry.class ); final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
// de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
// asks for it
if ( cfgService.getSettings().get( CHECK_NULLABILITY ) == null ) {
activationContext.getSessionFactory().getSessionFactoryOptions().setCheckNullability( false );
}
final BeanValidationEventListener listener = final BeanValidationEventListener listener =
new BeanValidationEventListener( validatorFactory, cfgService.getSettings(), classLoaderService ); new BeanValidationEventListener( validatorFactory, cfgService.getSettings(), classLoaderService );
final EventListenerRegistry listenerRegistry = serviceRegistry.requireService( 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 );
listenerRegistry.appendListeners( EventType.PRE_UPSERT, listener ); listenerRegistry.appendListeners( EventType.PRE_UPSERT, listener );
listener.initialize( cfgService.getSettings(), classLoaderService ); listener.initialize( cfgService.getSettings(), classLoaderService );
} }
private static void applyRelationalConstraints(ValidatorFactory factory, ActivationContext activationContext) { private static boolean isConstraintBasedValidationEnabled(ActivationContext context) {
final SessionFactoryServiceRegistry serviceRegistry = activationContext.getServiceRegistry(); if ( context.getServiceRegistry().requireService( ConfigurationService.class )
final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class ); .getSetting( APPLY_CONSTRAINTS, StandardConverters.BOOLEAN, true ) ) {
if ( !cfgService.getSetting( BeanValidationIntegrator.APPLY_CONSTRAINTS, StandardConverters.BOOLEAN, true ) ) { final Set<ValidationMode> modes = context.getValidationModes();
return modes.contains( ValidationMode.DDL )
|| modes.contains( ValidationMode.AUTO );
}
else {
LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" ); LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
return; return false;
} }
final Set<ValidationMode> modes = activationContext.getValidationModes();
if ( !modes.contains( ValidationMode.DDL ) && !modes.contains( ValidationMode.AUTO ) ) {
return;
} }
private static void applyRelationalConstraints(ValidatorFactory factory, ActivationContext context) {
if ( isConstraintBasedValidationEnabled( context ) ) {
final SessionFactoryServiceRegistry serviceRegistry = context.getServiceRegistry();
applyRelationalConstraints( applyRelationalConstraints(
factory, factory,
activationContext.getMetadata().getEntityBindings(), context.getMetadata().getEntityBindings(),
cfgService.getSettings(), serviceRegistry.requireService( ConfigurationService.class ).getSettings(),
serviceRegistry.requireService( JdbcServices.class ).getDialect(), serviceRegistry.requireService( JdbcServices.class ).getDialect(),
new ClassLoaderAccessImpl( null, new ClassLoaderAccessImpl( null, serviceRegistry.getService( ClassLoaderService.class ) )
serviceRegistry.getService( ClassLoaderService.class ) )
); );
} }
}
public static void applyRelationalConstraints( public static void applyRelationalConstraints(
ValidatorFactory factory, ValidatorFactory factory,
@ -160,21 +186,11 @@ class TypeSafeActivator {
ClassLoaderAccess classLoaderAccess) { ClassLoaderAccess classLoaderAccess) {
final Class<?>[] groupsArray = final Class<?>[] groupsArray =
buildGroupsForOperation( GroupsPerOperation.Operation.DDL, settings, classLoaderAccess ); buildGroupsForOperation( GroupsPerOperation.Operation.DDL, settings, classLoaderAccess );
final Set<Class<?>> groups = new HashSet<>( Arrays.asList( groupsArray ) ); final Set<Class<?>> groups = new HashSet<>( asList( groupsArray ) );
for ( PersistentClass persistentClass : persistentClasses ) { for ( PersistentClass persistentClass : persistentClasses ) {
final String className = persistentClass.getClassName(); final String className = persistentClass.getClassName();
if ( className == null || className.isEmpty() ) { if ( isNotEmpty( className ) ) {
continue; final Class<?> clazz = entityClass( classLoaderAccess, className );
}
Class<?> clazz;
try {
clazz = classLoaderAccess.classForName( className );
}
catch ( ClassLoadingException e ) {
throw new AssertionFailure( "Entity class not found", e );
}
try { try {
applyDDL( "", persistentClass, clazz, factory, groups, true, dialect ); applyDDL( "", persistentClass, clazz, factory, groups, true, dialect );
} }
@ -183,6 +199,16 @@ class TypeSafeActivator {
} }
} }
} }
}
private static Class<?> entityClass(ClassLoaderAccess classLoaderAccess, String className) {
try {
return classLoaderAccess.classForName( className );
}
catch (ClassLoadingException e) {
throw new AssertionFailure( "Entity class not found", e );
}
}
private static void applyDDL( private static void applyDDL(
String prefix, String prefix,
@ -193,8 +219,7 @@ class TypeSafeActivator {
boolean activateNotNull, boolean activateNotNull,
Dialect dialect) { Dialect dialect) {
final BeanDescriptor descriptor = factory.getValidator().getConstraintsForClass( clazz ); final BeanDescriptor descriptor = factory.getValidator().getConstraintsForClass( clazz );
//no bean level constraints can be applied, go to the properties //cno bean level constraints can be applied, go to the properties
for ( PropertyDescriptor propertyDesc : descriptor.getConstrainedProperties() ) { for ( PropertyDescriptor propertyDesc : descriptor.getConstrainedProperties() ) {
final Property property = final Property property =
findPropertyByName( persistentClass, prefix + propertyDesc.getPropertyName() ); findPropertyByName( persistentClass, prefix + propertyDesc.getPropertyName() );
@ -209,19 +234,16 @@ class TypeSafeActivator {
); );
if ( property.isComposite() && propertyDesc.isCascaded() ) { if ( property.isComposite() && propertyDesc.isCascaded() ) {
final Component component = (Component) property.getValue(); final Component component = (Component) property.getValue();
/*
* we can apply not null if the upper component lets us activate not null
* and if the property is not null.
* Otherwise, all sub columns should be left nullable
*/
final boolean canSetNotNullOnColumns = activateNotNull && hasNotNull;
applyDDL( applyDDL(
prefix + propertyDesc.getPropertyName() + ".", prefix + propertyDesc.getPropertyName() + ".",
persistentClass, persistentClass,
component.getComponentClass(), component.getComponentClass(),
factory, factory,
groups, groups,
canSetNotNullOnColumns, // we can apply not null if the upper component lets us
// activate not null and if the property is not null.
// Otherwise, all sub columns should be left nullable
activateNotNull && hasNotNull,
dialect dialect
); );
} }
@ -238,10 +260,7 @@ class TypeSafeActivator {
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 || !disjoint( descriptor.getGroups(), groups ) ) {
continue;
}
if ( canApplyNotNull ) { if ( canApplyNotNull ) {
hasNotNull = hasNotNull || applyNotNull( property, descriptor ); hasNotNull = hasNotNull || applyNotNull( property, descriptor );
} }
@ -252,13 +271,13 @@ class TypeSafeActivator {
applyMin( property, descriptor, dialect ); applyMin( property, descriptor, dialect );
applyMax( property, descriptor, dialect ); applyMax( property, descriptor, dialect );
// apply hibernate validator specific constraints - we cannot import any HV specific classes though! // 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 // No need to check explicitly for @Range. @Range is a composed constraint using @Min and @Max which
// will be taken care later // will be taken care later.
applyLength( property, descriptor, propertyDesc ); applyLength( property, descriptor, propertyDesc );
// pass an empty set as composing constraints inherit the main constraint and thus are matching already // pass an empty set as composing constraints inherit the main constraint and thus are matching already
boolean hasNotNullFromComposingConstraints = applyConstraints( final boolean hasNotNullFromComposingConstraints = applyConstraints(
descriptor.getComposingConstraints(), descriptor.getComposingConstraints(),
property, propertyDesc, null, property, propertyDesc, null,
canApplyNotNull, canApplyNotNull,
@ -267,6 +286,8 @@ class TypeSafeActivator {
hasNotNull = hasNotNull || hasNotNullFromComposingConstraints; hasNotNull = hasNotNull || hasNotNullFromComposingConstraints;
} }
}
return hasNotNull; return hasNotNull;
} }
@ -275,11 +296,9 @@ class TypeSafeActivator {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final ConstraintDescriptor<Min> minConstraint = (ConstraintDescriptor<Min>) descriptor; final ConstraintDescriptor<Min> minConstraint = (ConstraintDescriptor<Min>) descriptor;
final long min = minConstraint.getAnnotation().value(); final long min = minConstraint.getAnnotation().value();
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column column ) { if ( selectable instanceof Column column ) {
final String checkConstraint = column.getQuotedName( dialect ) + ">=" + min; applySQLCheck( column, column.getQuotedName( dialect ) + ">=" + min );
applySQLCheck( column, checkConstraint );
} }
} }
} }
@ -290,25 +309,23 @@ class TypeSafeActivator {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final ConstraintDescriptor<Max> maxConstraint = (ConstraintDescriptor<Max>) descriptor; final ConstraintDescriptor<Max> maxConstraint = (ConstraintDescriptor<Max>) descriptor;
final long max = maxConstraint.getAnnotation().value(); final long max = maxConstraint.getAnnotation().value();
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column column ) { if ( selectable instanceof Column column ) {
final String checkConstraint = column.getQuotedName( dialect ) + "<=" + max; applySQLCheck( column, column.getQuotedName( dialect ) + "<=" + max );
applySQLCheck( column, checkConstraint );
} }
} }
} }
} }
private static void applySQLCheck(Column col, String checkConstraint) { private static void applySQLCheck(Column column, String checkConstraint) {
// need to check whether the new check is already part of the existing check, // need to check whether the new check is already part of the existing check,
// because applyDDL can be called multiple times // because applyDDL can be called multiple times
for ( CheckConstraint constraint : col.getCheckConstraints() ) { for ( CheckConstraint constraint : column.getCheckConstraints() ) {
if ( constraint.getConstraint().equalsIgnoreCase( checkConstraint ) ) { if ( constraint.getConstraint().equalsIgnoreCase( checkConstraint ) ) {
return; //EARLY EXIT return; //EARLY EXIT
} }
} }
col.addCheckConstraint( new CheckConstraint( checkConstraint ) ); column.addCheckConstraint( new CheckConstraint( checkConstraint ) );
} }
private static boolean applyNotNull(Property property, ConstraintDescriptor<?> descriptor) { private static boolean applyNotNull(Property property, ConstraintDescriptor<?> descriptor) {
@ -320,11 +337,11 @@ class TypeSafeActivator {
|| NotBlank.class.equals(annotationType)) { || NotBlank.class.equals(annotationType)) {
// single table inheritance should not be forced to null due to shared state // single table inheritance should not be forced to null due to shared state
if ( !( property.getPersistentClass() instanceof SingleTableSubclass ) ) { if ( !( property.getPersistentClass() instanceof SingleTableSubclass ) ) {
//composite should not add not-null on all columns // composite should not add not-null on all columns
if ( !property.isComposite() ) { if ( !property.isComposite() ) {
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column ) { if ( selectable instanceof Column column ) {
((Column) selectable).setNullable( false ); column.setNullable( false );
} }
else { else {
LOG.debugf( LOG.debugf(
@ -345,10 +362,9 @@ class TypeSafeActivator {
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")
ConstraintDescriptor<Digits> digitsConstraint = (ConstraintDescriptor<Digits>) descriptor; final ConstraintDescriptor<Digits> digitsConstraint = (ConstraintDescriptor<Digits>) descriptor;
int integerDigits = digitsConstraint.getAnnotation().integer(); final int integerDigits = digitsConstraint.getAnnotation().integer();
int fractionalDigits = digitsConstraint.getAnnotation().fraction(); final int fractionalDigits = digitsConstraint.getAnnotation().fraction();
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column column ) { if ( selectable instanceof Column column ) {
column.setPrecision( integerDigits + fractionalDigits ); column.setPrecision( integerDigits + fractionalDigits );
@ -363,9 +379,8 @@ class TypeSafeActivator {
if ( Size.class.equals( descriptor.getAnnotation().annotationType() ) if ( Size.class.equals( descriptor.getAnnotation().annotationType() )
&& String.class.equals( propertyDescriptor.getElementClass() ) ) { && String.class.equals( propertyDescriptor.getElementClass() ) ) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ConstraintDescriptor<Size> sizeConstraint = (ConstraintDescriptor<Size>) descriptor; final ConstraintDescriptor<Size> sizeConstraint = (ConstraintDescriptor<Size>) descriptor;
int max = sizeConstraint.getAnnotation().max(); final int max = sizeConstraint.getAnnotation().max();
for ( Column col : property.getColumns() ) { for ( Column col : property.getColumns() ) {
if ( max < Integer.MAX_VALUE ) { if ( max < Integer.MAX_VALUE ) {
col.setLength( max ); col.setLength( max );
@ -375,12 +390,9 @@ class TypeSafeActivator {
} }
private static void applyLength(Property property, ConstraintDescriptor<?> descriptor, PropertyDescriptor propertyDescriptor) { private static void applyLength(Property property, ConstraintDescriptor<?> descriptor, PropertyDescriptor propertyDescriptor) {
if ( "org.hibernate.validator.constraints.Length".equals( if ( isValidatorLengthAnnotation( descriptor )
descriptor.getAnnotation().annotationType().getName()
)
&& String.class.equals( propertyDescriptor.getElementClass() ) ) { && String.class.equals( propertyDescriptor.getElementClass() ) ) {
int max = (Integer) descriptor.getAttributes().get( "max" ); final int max = (Integer) descriptor.getAttributes().get( "max" );
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column column ) { if ( selectable instanceof Column column ) {
if ( max < Integer.MAX_VALUE ) { if ( max < Integer.MAX_VALUE ) {
@ -391,18 +403,21 @@ class TypeSafeActivator {
} }
} }
private static boolean isValidatorLengthAnnotation(ConstraintDescriptor<?> descriptor) {
return "org.hibernate.validator.constraints.Length"
.equals( descriptor.getAnnotation().annotationType().getName() );
}
/** /**
* Locate the property by path in a recursive way, including IdentifierProperty in the loop if propertyName is * Locate the property by path in a recursive way, including IdentifierProperty in the loop if propertyName is
* {@code null}. If propertyName is {@code null} or empty, the IdentifierProperty is returned * {@code null}. If propertyName is {@code null} or empty, the IdentifierProperty is returned
*/ */
private static Property findPropertyByName(PersistentClass associatedClass, String propertyName) { private static Property findPropertyByName(PersistentClass associatedClass, String propertyName) {
Property property = null; Property property = null;
Property idProperty = associatedClass.getIdentifierProperty(); final Property idProperty = associatedClass.getIdentifierProperty();
String idName = idProperty != null ? idProperty.getName() : null; final String idName = idProperty != null ? idProperty.getName() : null;
try { try {
if ( propertyName == null if ( isEmpty( propertyName ) || propertyName.equals( idName ) ) {
|| propertyName.isEmpty()
|| propertyName.equals( idName ) ) {
//default to id //default to id
property = idProperty; property = idProperty;
} }
@ -411,9 +426,9 @@ class TypeSafeActivator {
property = idProperty; property = idProperty;
propertyName = propertyName.substring( idName.length() + 1 ); propertyName = propertyName.substring( idName.length() + 1 );
} }
StringTokenizer st = new StringTokenizer( propertyName, ".", false ); final StringTokenizer tokens = new StringTokenizer( propertyName, ".", false );
while ( st.hasMoreElements() ) { while ( tokens.hasMoreTokens() ) {
String element = (String) st.nextElement(); final String element = tokens.nextToken();
if ( property == null ) { if ( property == null ) {
property = associatedClass.getProperty( element ); property = associatedClass.getProperty( element );
} }
@ -421,20 +436,23 @@ class TypeSafeActivator {
if ( !property.isComposite() ) { if ( !property.isComposite() ) {
return null; return null;
} }
else {
property = ( (Component) property.getValue() ).getProperty( element ); property = ( (Component) property.getValue() ).getProperty( element );
} }
} }
} }
} }
}
catch ( MappingException e ) { catch ( MappingException e ) {
try { try {
//if we do not find it try to check the identifier mapper //if we do not find it try to check the identifier mapper
if ( associatedClass.getIdentifierMapper() == null ) { if ( associatedClass.getIdentifierMapper() == null ) {
return null; return null;
} }
StringTokenizer st = new StringTokenizer( propertyName, ".", false ); else {
while ( st.hasMoreElements() ) { final StringTokenizer tokens = new StringTokenizer( propertyName, ".", false );
String element = (String) st.nextElement(); while ( tokens.hasMoreTokens() ) {
final String element = tokens.nextToken();
if ( property == null ) { if ( property == null ) {
property = associatedClass.getIdentifierMapper().getProperty( element ); property = associatedClass.getIdentifierMapper().getProperty( element );
} }
@ -442,10 +460,13 @@ class TypeSafeActivator {
if ( !property.isComposite() ) { if ( !property.isComposite() ) {
return null; return null;
} }
else {
property = ( (Component) property.getValue() ).getProperty( element ); property = ( (Component) property.getValue() ).getProperty( element );
} }
} }
} }
}
}
catch ( MappingException ee ) { catch ( MappingException ee ) {
return null; return null;
} }
@ -453,7 +474,7 @@ class TypeSafeActivator {
return property; return property;
} }
private static ValidatorFactory getValidatorFactory(ActivationContext activationContext) { private static ValidatorFactory getValidatorFactory(ActivationContext context) {
// IMPL NOTE : We can either be provided a ValidatorFactory or make one. We can be provided // IMPL NOTE : We can either be provided a ValidatorFactory or make one. We can be provided
// a ValidatorFactory in 2 different ways. So here we "get" a ValidatorFactory in the following order: // a ValidatorFactory in 2 different ways. So here we "get" a ValidatorFactory in the following order:
// 1) Look into SessionFactoryOptions.getValidatorFactoryReference() // 1) Look into SessionFactoryOptions.getValidatorFactoryReference()
@ -461,15 +482,17 @@ class TypeSafeActivator {
// 3) build a new ValidatorFactory // 3) build a new ValidatorFactory
// 1 - look in SessionFactoryOptions.getValidatorFactoryReference() // 1 - look in SessionFactoryOptions.getValidatorFactoryReference()
ValidatorFactory factory = resolveProvidedFactory( activationContext.getSessionFactory().getSessionFactoryOptions() ); final ValidatorFactory providedFactory =
if ( factory != null ) { resolveProvidedFactory( context.getSessionFactory().getSessionFactoryOptions() );
return factory; if ( providedFactory != null ) {
return providedFactory;
} }
// 2 - look in ConfigurationService // 2 - look in ConfigurationService
factory = resolveProvidedFactory( activationContext.getServiceRegistry().requireService( ConfigurationService.class ) ); final ValidatorFactory configuredFactory =
if ( factory != null ) { resolveProvidedFactory( context.getServiceRegistry().requireService( ConfigurationService.class ) );
return factory; if ( configuredFactory != null ) {
return configuredFactory;
} }
// 3 - build our own // 3 - build our own
@ -486,10 +509,10 @@ class TypeSafeActivator {
if ( validatorFactoryReference == null ) { if ( validatorFactoryReference == null ) {
return null; return null;
} }
try { else if ( validatorFactoryReference instanceof ValidatorFactory result ) {
return (ValidatorFactory) validatorFactoryReference; return result;
} }
catch ( ClassCastException e ) { else {
throw new IntegrationException( throw new IntegrationException(
String.format( String.format(
Locale.ENGLISH, Locale.ENGLISH,
@ -505,42 +528,29 @@ class TypeSafeActivator {
private static ValidatorFactory resolveProvidedFactory(ConfigurationService cfgService) { private static ValidatorFactory resolveProvidedFactory(ConfigurationService cfgService) {
return cfgService.getSetting( return cfgService.getSetting(
JPA_VALIDATION_FACTORY, JPA_VALIDATION_FACTORY,
value -> { value -> validatorFactory( value, JPA_VALIDATION_FACTORY ),
try {
return (ValidatorFactory) value;
}
catch ( ClassCastException e ) {
throw new IntegrationException(
String.format(
Locale.ENGLISH,
"ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s",
JPA_VALIDATION_FACTORY,
ValidatorFactory.class.getName(),
value.getClass().getName()
)
);
}
},
cfgService.getSetting( cfgService.getSetting(
JAKARTA_VALIDATION_FACTORY, JAKARTA_VALIDATION_FACTORY,
value -> { value -> validatorFactory( value, JAKARTA_VALIDATION_FACTORY ),
try {
return (ValidatorFactory) value;
}
catch ( ClassCastException e ) {
throw new IntegrationException(
String.format(
Locale.ENGLISH,
"ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s",
JAKARTA_VALIDATION_FACTORY,
ValidatorFactory.class.getName(),
value.getClass().getName()
)
);
}
},
null null
) )
); );
} }
private static ValidatorFactory validatorFactory(Object value, String setting) {
if ( value instanceof ValidatorFactory validatorFactory ) {
return validatorFactory;
}
else {
throw new IntegrationException(
String.format(
Locale.ENGLISH,
"ValidatorFactory reference (provided via '%s' setting) was not an instance of '%s': %s",
setting,
ValidatorFactory.class.getName(),
value.getClass().getName()
)
);
}
}
} }