Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,17 @@ public interface PredefinedScopeHibernateValidatorConfiguration extends BaseHibe
@Incubating
@Deprecated
PredefinedScopeHibernateValidatorConfiguration initializeLocales(Set<Locale> locales);

/**
* Specify whether to append the {@link #builtinConstraints(Set) built-in constraints} and {@link #initializeBeanMetaData(Set) beans to initialize}
* with constraints and beans provided only through XML mapping.
* <p>
* This option is enabled by default.
*
* @param include Whether to include the beans defined only in xml as part of the {@link #initializeBeanMetaData(Set) set of beans to initialize}
* and also add built-in constraints used only in xml definitions as part of the {@link #builtinConstraints(Set) set of built-in constraints}.
* @return {@code this} for chaining configuration method calls.
*/
@Incubating
PredefinedScopeHibernateValidatorConfiguration includeBeansAndConstraintsDefinedOnlyInXml(boolean include);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class PredefinedScopeConfigurationImpl extends AbstractConfigurationImpl<

private Set<Class<?>> beanClassesToInitialize;

private boolean includeBeansAndConstraintsDefinedOnlyInXml = true;

public PredefinedScopeConfigurationImpl(BootstrapState state) {
super( state );
}
Expand Down Expand Up @@ -58,6 +60,10 @@ public Set<Class<?>> getBeanClassesToInitialize() {
return beanClassesToInitialize;
}

public boolean isIncludeBeansAndConstraintsDefinedOnlyInXml() {
return includeBeansAndConstraintsDefinedOnlyInXml;
}

@Override
@Deprecated
public PredefinedScopeHibernateValidatorConfiguration initializeLocales(Set<Locale> localesToInitialize) {
Expand All @@ -66,6 +72,12 @@ public PredefinedScopeHibernateValidatorConfiguration initializeLocales(Set<Loca
return thisAsT();
}

@Override
public PredefinedScopeHibernateValidatorConfiguration includeBeansAndConstraintsDefinedOnlyInXml(boolean include) {
this.includeBeansAndConstraintsDefinedOnlyInXml = include;
return thisAsT();
}

@Override
protected boolean preloadResourceBundles() {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.lang.invoke.MethodHandles;
import java.time.Duration;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -146,7 +147,9 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
this.propertyNodeNameProvider = ValidatorFactoryConfigurationHelper.determinePropertyNodeNameProvider( hibernateSpecificConfig, properties, externalClassLoader );

this.valueExtractorManager = new ValueExtractorManager( configurationState.getValueExtractors() );
ConstraintHelper constraintHelper = ConstraintHelper.forBuiltinConstraints( hibernateSpecificConfig.getBuiltinConstraints() );
ConstraintHelper constraintHelper = ConstraintHelper.forBuiltinConstraints(
hibernateSpecificConfig.getBuiltinConstraints(),
hibernateSpecificConfig.isIncludeBeansAndConstraintsDefinedOnlyInXml() );
TypeResolutionHelper typeResolutionHelper = new TypeResolutionHelper();

ConstraintCreationContext constraintCreationContext = new ConstraintCreationContext( constraintHelper,
Expand Down Expand Up @@ -188,9 +191,14 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
// or from programmatic mappings
registerCustomConstraintValidators( constraintMappings, constraintHelper );

Set<Class<?>> beanClassesToInitialize = new HashSet<>( hibernateSpecificConfig.getBeanClassesToInitialize() );

XmlMetaDataProvider xmlMetaDataProvider;
if ( mappingParser != null && mappingParser.createConstrainedElements() ) {
xmlMetaDataProvider = new XmlMetaDataProvider( mappingParser );
if ( hibernateSpecificConfig.isIncludeBeansAndConstraintsDefinedOnlyInXml() ) {
beanClassesToInitialize.addAll( xmlMetaDataProvider.configuredBeanClasses() );
}
}
else {
xmlMetaDataProvider = null;
Expand All @@ -205,7 +213,7 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
buildMetaDataProviders( constraintCreationContext, xmlMetaDataProvider, constraintMappings ),
methodValidationConfiguration,
determineBeanMetaDataClassNormalizer( hibernateSpecificConfig ),
hibernateSpecificConfig.getBeanClassesToInitialize()
beanClassesToInitialize
);

if ( LOG.isDebugEnabled() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import jakarta.validation.constraints.Size;
import jakarta.validation.constraintvalidation.ValidationTarget;

import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.constraints.BitcoinAddress;
import org.hibernate.validator.constraints.CodePointLength;
import org.hibernate.validator.constraints.ConstraintComposition;
Expand Down Expand Up @@ -372,7 +373,7 @@
* @author Gunnar Morling
* @author Guillaume Smet
*/
public class ConstraintHelper {
public abstract class ConstraintHelper {

public static final String GROUPS = "groups";
public static final String PAYLOAD = "payload";
Expand All @@ -385,9 +386,6 @@ public class ConstraintHelper {
private static final String JODA_TIME_CLASS_NAME = "org.joda.time.ReadableInstant";
private static final String JAVA_MONEY_CLASS_NAME = "javax.money.MonetaryAmount";

@Immutable
private final Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> enabledBuiltinConstraints;

private final ConcurrentMap<Class<? extends Annotation>, Boolean> externalConstraints = new ConcurrentHashMap<>();

private final ConcurrentMap<Class<? extends Annotation>, Boolean> multiValueConstraints = new ConcurrentHashMap<>();
Expand All @@ -399,21 +397,26 @@ public class ConstraintHelper {
private Boolean jodaTimeInClassPath;

public static ConstraintHelper forAllBuiltinConstraints() {
return new ConstraintHelper( new HashSet<>( Arrays.asList( BuiltinConstraint.values() ) ) );
return new StaticConstraintHelper();
}

public static ConstraintHelper forBuiltinConstraints(Set<String> enabledConstraints) {
return new ConstraintHelper( BuiltinConstraint.resolve( enabledConstraints ) );
public static ConstraintHelper forBuiltinConstraints(Set<String> enabledConstraints, boolean attemptToResolveMissingBuiltInConstraintsOnTheFly) {
Set<BuiltinConstraint> builtinConstraints = BuiltinConstraint.resolve( enabledConstraints );
if ( attemptToResolveMissingBuiltInConstraintsOnTheFly ) {
return new DynamicConstraintHelper( builtinConstraints );
}
else {
return new StaticConstraintHelper( builtinConstraints );
}
}

@SuppressWarnings("deprecation")
private ConstraintHelper(Set<BuiltinConstraint> enabledBuiltinConstraints) {
protected Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> resolve(Set<BuiltinConstraint> enabledBuiltinConstraints) {
if ( enabledBuiltinConstraints.isEmpty() ) {
this.enabledBuiltinConstraints = Collections.emptyMap();
return;
return Collections.emptyMap();
}

Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> tmpConstraints = new HashMap<>();
Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> tmpConstraints = new HashMap<>();

// Bean Validation constraints

Expand Down Expand Up @@ -832,21 +835,27 @@ private ConstraintHelper(Set<BuiltinConstraint> enabledBuiltinConstraints) {
putBuiltinConstraint( tmpConstraints, BitcoinAddress.class, BitcoinAddressValidator.class );
}

this.enabledBuiltinConstraints = Collections.unmodifiableMap( tmpConstraints );
return tmpConstraints;
}

private static <A extends Annotation> void putBuiltinConstraint(Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType) {
private static <A extends Annotation> void putBuiltinConstraint(
Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType
) {
validators.put( constraintType, Collections.emptyList() );
}

private static <A extends Annotation> void putBuiltinConstraint(Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType, Class<? extends ConstraintValidator<A, ?>> validatorType) {
private static <A extends Annotation> void putBuiltinConstraint(
Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType, Class<? extends ConstraintValidator<A, ?>> validatorType
) {
validators.put( constraintType, Collections.singletonList( ConstraintValidatorDescriptor.forBuiltinClass( validatorType, constraintType ) ) );
}

private static <A extends Annotation> void putBuiltinConstraints(Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType, List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes) {
private static <A extends Annotation> void putBuiltinConstraints(
Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> validators,
Class<A> constraintType, List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes
) {
List<ConstraintValidatorDescriptor<?>> descriptors = new ArrayList<>( validatorTypes.size() );

for ( Class<? extends ConstraintValidator<A, ?>> validatorType : validatorTypes ) {
Expand All @@ -873,14 +882,13 @@ public static Set<String> getBuiltinConstraints() {
* <li>internally registered validators for built-in constraints</li>
* <li>XML configuration and</li>
* <li>programmatically registered validators (see
* {@link org.hibernate.validator.cfg.ConstraintMapping#constraintDefinition(Class)}).</li>
* {@link ConstraintMapping#constraintDefinition(Class)}).</li>
* </ul>
*
* The result is cached internally.
*
* @param annotationType The constraint annotation type.
* @param <A> the type of the annotation
*
* @return The validator classes for the given type.
*/
public <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getAllValidatorDescriptors(Class<A> annotationType) {
Expand All @@ -895,7 +903,6 @@ public <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getAllValid
* @param annotationType The annotation of interest.
* @param validationTarget The target, either annotated element or parameters.
* @param <A> the type of the annotation
*
* @return A list with matching validator descriptors.
*/
public <A extends Annotation> List<ConstraintValidatorDescriptor<A>> findValidatorDescriptors(Class<A> annotationType, ValidationTarget validationTarget) {
Expand Down Expand Up @@ -937,9 +944,8 @@ public <A extends Annotation> void putValidatorDescriptors(Class<A> annotationTy
* Checks whether a given annotation is a multi value constraint or not.
*
* @param annotationType the annotation type to check.
*
* @return {@code true} if the specified annotation is a multi value constraints, {@code false}
* otherwise.
* otherwise.
*/
public boolean isMultiValueConstraint(Class<? extends Annotation> annotationType) {
if ( isJdkAnnotation( annotationType ) ) {
Expand Down Expand Up @@ -974,7 +980,6 @@ public boolean isMultiValueConstraint(Class<? extends Annotation> annotationType
*
* @param multiValueConstraint the multi-value constraint annotation from which to retrieve the contained constraints
* @param <A> the type of the annotation
*
* @return A list of constraint annotations, may be empty but never {@code null}.
*/
public <A extends Annotation> List<Annotation> getConstraintsFromMultiValueConstraint(A multiValueConstraint) {
Expand All @@ -997,7 +1002,6 @@ public <A extends Annotation> List<Annotation> getConstraintsFromMultiValueConst
* </ul>
*
* @param annotationType The annotation type to test.
*
* @return {@code true} if the annotation fulfills the above conditions, {@code false} otherwise.
*/
public boolean isConstraintAnnotation(Class<? extends Annotation> annotationType) {
Expand Down Expand Up @@ -1139,32 +1143,88 @@ private boolean isJavaMoneyInClasspath() {
* Returns the default validators for the given constraint type.
*
* @param annotationType The constraint annotation type.
*
* @return A list with the default validators as retrieved from
* {@link Constraint#validatedBy()} or the list of validators for
* built-in constraints.
* {@link Constraint#validatedBy()} or the list of validators for
* built-in constraints.
*/
@SuppressWarnings("unchecked")
private <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getDefaultValidatorDescriptors(Class<A> annotationType) {
//safe cause all CV for a given annotation A are CV<A, ?>
final List<ConstraintValidatorDescriptor<A>> builtInValidators = (List<ConstraintValidatorDescriptor<A>>) enabledBuiltinConstraints
.get( annotationType );
protected abstract <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getDefaultValidatorDescriptors(Class<A> annotationType);

private static boolean isClassPresent(String className) {
return IsClassPresent.action( className, ConstraintHelper.class.getClassLoader() );
}

private static class StaticConstraintHelper extends ConstraintHelper {

@Immutable
private final Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> enabledBuiltinConstraints;

private StaticConstraintHelper() {
this( new HashSet<>( Arrays.asList( BuiltinConstraint.values() ) ) );
}

if ( builtInValidators != null ) {
return builtInValidators;
private StaticConstraintHelper(Set<BuiltinConstraint> builtinConstraints) {
this.enabledBuiltinConstraints = Collections.unmodifiableMap( resolve( builtinConstraints ) );
}

Class<? extends ConstraintValidator<A, ?>>[] validatedBy = (Class<? extends ConstraintValidator<A, ?>>[]) annotationType
.getAnnotation( Constraint.class )
.validatedBy();
@SuppressWarnings("unchecked")
@Override
protected <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getDefaultValidatorDescriptors(Class<A> annotationType) {
//safe cause all CV for a given annotation A are CV<A, ?>
final List<ConstraintValidatorDescriptor<A>> builtInValidators = (List<ConstraintValidatorDescriptor<A>>) enabledBuiltinConstraints
.get( annotationType );

return Stream.of( validatedBy )
.map( c -> ConstraintValidatorDescriptor.forClass( c, annotationType ) )
.collect( Collectors.collectingAndThen( Collectors.toList(), CollectionHelper::toImmutableList ) );
if ( builtInValidators != null ) {
return builtInValidators;
}

Class<? extends ConstraintValidator<A, ?>>[] validatedBy = (Class<? extends ConstraintValidator<A, ?>>[]) annotationType
.getAnnotation( Constraint.class )
.validatedBy();

return Stream.of( validatedBy )
.map( c -> ConstraintValidatorDescriptor.forClass( c, annotationType ) )
.collect( Collectors.collectingAndThen( Collectors.toList(), CollectionHelper::toImmutableList ) );
}
}

private static boolean isClassPresent(String className) {
return IsClassPresent.action( className, ConstraintHelper.class.getClassLoader() );
private static class DynamicConstraintHelper extends ConstraintHelper {

@Immutable
private final Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> enabledBuiltinConstraints;

private DynamicConstraintHelper(Set<BuiltinConstraint> initialConstraints) {
this.enabledBuiltinConstraints = new HashMap<>( resolve( initialConstraints ) );
}

@SuppressWarnings("unchecked")
@Override
protected <A extends Annotation> List<ConstraintValidatorDescriptor<A>> getDefaultValidatorDescriptors(Class<A> annotationType) {
//safe cause all CV for a given annotation A are CV<A, ?>
final List<ConstraintValidatorDescriptor<A>> builtInValidators = (List<ConstraintValidatorDescriptor<A>>) enabledBuiltinConstraints
.get( annotationType );

if ( builtInValidators != null ) {
return builtInValidators;
}
else {
// let's give it a try and see if we can find this constraint among the built-in ones:
Set<BuiltinConstraint> builtinConstraints = BuiltinConstraint.resolve( Collections.singleton( annotationType.getName() ) );
if ( !builtinConstraints.isEmpty() ) {
Map<Class<? extends Annotation>, List<? extends ConstraintValidatorDescriptor<?>>> additionalDescriptors = resolve( builtinConstraints );
enabledBuiltinConstraints.putAll( additionalDescriptors );
return (List<ConstraintValidatorDescriptor<A>>) additionalDescriptors.get( annotationType );
}
}

Class<? extends ConstraintValidator<A, ?>>[] validatedBy = (Class<? extends ConstraintValidator<A, ?>>[]) annotationType
.getAnnotation( Constraint.class )
.validatedBy();

return Stream.of( validatedBy )
.map( c -> ConstraintValidatorDescriptor.forClass( c, annotationType ) )
.collect( Collectors.collectingAndThen( Collectors.toList(), CollectionHelper::toImmutableList ) );
}
}

/**
Expand All @@ -1183,8 +1243,10 @@ private <A extends Annotation> void put(Class<A> annotationType, List<Constraint
constraintValidatorDescriptors.put( annotationType, validatorDescriptors );
}

private <A extends Annotation> List<ConstraintValidatorDescriptor<A>> computeIfAbsent(Class<A> annotationType,
Function<? super Class<A>, List<ConstraintValidatorDescriptor<A>>> mappingFunction) {
private <A extends Annotation> List<ConstraintValidatorDescriptor<A>> computeIfAbsent(
Class<A> annotationType,
Function<? super Class<A>, List<ConstraintValidatorDescriptor<A>>> mappingFunction
) {
return (List<ConstraintValidatorDescriptor<A>>) constraintValidatorDescriptors.computeIfAbsent(
annotationType,
(Function<? super Class<? extends Annotation>, ? extends List<? extends ConstraintValidatorDescriptor<?>>>) mappingFunction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
Expand Down Expand Up @@ -66,4 +67,9 @@ public <T> BeanConfiguration<T> getBeanConfiguration(Class<T> beanClass) {
public AnnotationProcessingOptions getAnnotationProcessingOptions() {
return annotationProcessingOptions;
}

public Set<Class<?>> configuredBeanClasses() {
return configuredBeans.values().stream().map( BeanConfiguration::getBeanClass )
.collect( Collectors.toSet() );
}
}
Loading