Skip to content

Commit

Permalink
HV-1949 Load constraint validators from a Service Loader first
Browse files Browse the repository at this point in the history
- since there's no control over them and we cannot override a validator coming from a service loader
  • Loading branch information
marko-bekhta authored and gsmet committed Jun 16, 2023
1 parent 7c285c9 commit 2065108
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineExternalClassLoader;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineFailFast;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineScriptEvaluatorFactory;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineServiceLoadedConstraintMappings;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTemporalValidationTolerance;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTraversableResolverResultCacheEnabled;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.logValidatorFactoryScopedConfiguration;
Expand Down Expand Up @@ -152,6 +153,18 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
ExecutableHelper executableHelper = new ExecutableHelper( typeResolutionHelper );
JavaBeanHelper javaBeanHelper = new JavaBeanHelper( getterPropertySelectionStrategy, propertyNodeNameProvider );

// first we want to register any validators coming from a service loader. Since they are just loaded and there's
// no control over them (include/exclude the ones that already exists from any other sources etc.)
registerCustomConstraintValidators(
determineServiceLoadedConstraintMappings(
typeResolutionHelper,
javaBeanHelper,
externalClassLoader
),
constraintHelper );

// we parse all XML mappings but only register constraint validators and delay constraint mappings building till
// we collect all the constraint validators.
// HV-302; don't load XmlMappingParser if not necessary
MappingXmlParser mappingParser = null;
if ( !configurationState.getMappingStreams().isEmpty() ) {
Expand All @@ -169,6 +182,8 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
)
);

// now the final step of registering any constraint validators that can come either from ConstraintMappingContributors
// or from programmatic mappings
registerCustomConstraintValidators( constraintMappings, constraintHelper );

XmlMetaDataProvider xmlMetaDataProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,6 @@ static Set<DefaultConstraintMapping> determineConstraintMappings(TypeResolutionH
* these programmatically defined mappings into account when checking for constraint definition uniqueness
*/
constraintMappings.addAll( hibernateConfiguration.getProgrammaticMappings() );

// service loader based config
ConstraintMappingContributor serviceLoaderBasedContributor = new ServiceLoaderBasedConstraintMappingContributor(
typeResolutionHelper,
externalClassLoader != null ? externalClassLoader : run( GetClassLoader.fromContext() ) );
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( javaBeanHelper, constraintMappings );
serviceLoaderBasedContributor.createConstraintMappings( builder );
}

// XML-defined constraint mapping contributors
Expand All @@ -93,6 +86,22 @@ static Set<DefaultConstraintMapping> determineConstraintMappings(TypeResolutionH
return constraintMappings;
}

static Set<DefaultConstraintMapping> determineServiceLoadedConstraintMappings(
TypeResolutionHelper typeResolutionHelper,
JavaBeanHelper javaBeanHelper, ClassLoader externalClassLoader) {
Set<DefaultConstraintMapping> constraintMappings = newHashSet();

// service loader based config
ConstraintMappingContributor serviceLoaderBasedContributor = new ServiceLoaderBasedConstraintMappingContributor(
typeResolutionHelper,
externalClassLoader != null ? externalClassLoader : run( GetClassLoader.fromContext() )
);
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder(
javaBeanHelper, constraintMappings );
serviceLoaderBasedContributor.createConstraintMappings( builder );
return constraintMappings;
}

static boolean checkPropertiesForBoolean(Map<String, String> properties, String propertyKey, boolean programmaticValue) {
boolean value = programmaticValue;
String propertyStringValue = properties.get( propertyKey );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineExternalClassLoader;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineFailFast;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineScriptEvaluatorFactory;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineServiceLoadedConstraintMappings;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTemporalValidationTolerance;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTraversableResolverResultCacheEnabled;
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.logValidatorFactoryScopedConfiguration;
Expand Down Expand Up @@ -185,6 +186,19 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
ValidatorFactoryConfigurationHelper.determinePropertyNodeNameProvider( hibernateSpecificConfig, properties, externalClassLoader ) );
this.beanMetadataClassNormalizer = determineBeanMetaDataClassNormalizer( hibernateSpecificConfig );

// first we want to register any validators coming from a service loader. Since they are just loaded and there's
// no control over them (include/exclude the ones that already exists from any other sources etc.)
registerCustomConstraintValidators(
determineServiceLoadedConstraintMappings(
typeResolutionHelper,
javaBeanHelper,
externalClassLoader
),
constraintHelper );

// we parse all XML mappings but only register constraint validators and delay constraint mappings building till
// we collect all the constraint validators.
// HV-302; don't load XmlMappingParser if not necessary
MappingXmlParser mappingParser = null;
if ( !configurationState.getMappingStreams().isEmpty() ) {
mappingParser = new MappingXmlParser( constraintCreationContext,
Expand All @@ -201,9 +215,10 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
)
);

// now the final step of registering any constraint validators that can come either from ConstraintMappingContributors
// or from programmatic mappings
registerCustomConstraintValidators( constraintMappings, constraintHelper );

// HV-302; don't load XmlMappingParser if not necessary
if ( mappingParser != null && mappingParser.createConstrainedElements() ) {
this.xmlMetaDataProvider = new XmlMetaDataProvider( mappingParser );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,25 @@ public void constraintAppliedProgrammaticallyDefinitionIsAppliedThroughXml() {
);
}

@Test
public void constraintValidatorLoadedByServiceLoaderOverriddenByProgrammaticDefinition() {
final HibernateValidatorConfiguration configuration = ValidatorUtil.getConfiguration();
configuration.externalClassLoader( new ServiceLoaderTestingClassLoader() );

ConstraintMapping constraintMapping = configuration.createConstraintMapping();
configuration.addMapping( constraintMapping );

constraintMapping.constraintDefinition( MyOtherConstraint.class )
.includeExistingValidators( false )
.validatedBy( MyOtherConstraint.MyOtherOtherConstraintValidator.class );

final ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
final Validator validator = validatorFactory.getValidator();

assertNoViolations( validator.validate( new Foo() ) );
assertNoViolations( validator.validate( new Bar() ) );
}

public static class Foo {
public String string;
}
Expand Down

0 comments on commit 2065108

Please sign in to comment.