Search code examples
bean-validationhibernate-validator

How to pair annotation to custom ConstraintValidator in spring multimodule project, when annotation is in different module than implementation


MWE(minimal working example): https://github.com/alfonz19/validator-fail-mwe

TLDR: only xml-based configuration of validation does not work in multimodule project where annotation to ConstraintViolation implementation is paired using ServiceLoader. Annotation-based config works always, xml-based does also work when all is put into one module. Please any hints/idea/suggestions what to debug.


Update, famous breakthrough:

if app starts fresh, and first request is served by REST (annotation-based configuration), something missing is probably initialized and all works, including xml-based configuration validation. All good! If app starts fresh, and first request is served via kafka (probably not important) which leads into xml-based configuration logic, something is destroyed(missing initialization finished unsuccessfully) and from that point on nothing works, including rest.


If annotation and implementation is in same module, we can trivially bind them together using:

@Constraint(validatedBy = HasClassTypeValidator.class)

or we can(and must in case of multi-module layout) put there:

@Constraint(validatedBy = {})

and define the pairing in ServiceLoader configuration file. So far all good. But I'd like to add validation to auto-generated sources, where I cannot influence them in any way. Easy! You just specify META-INF/validation.xml:

<validation-config
    xmlns="http://xmlns.jcp.org/xml/ns/validation/configuration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
                    http://xmlns.jcp.org/xml/ns/validation/configuration
                    http://xmlns.jcp.org/xml/ns/validation/configuration/validation-configuration-2.0.xsd"
    version="2.0">

  <constraint-mapping>/META-INF/validation-constraints.xml</constraint-mapping>
</validation-config>

and related validation-constraints.xml file:

<constraint-mappings
    xmlns="http://xmlns.jcp.org/xml/ns/validation/mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/mapping
            http://xmlns.jcp.org/xml/ns/validation/mapping/validation-mapping-2.0.xsd"
    version="2.0">

  <bean class="Whatever">
    <class ignore-annotations="false"/>

    <getter name="whatever" ignore-annotations="false">
      <constraint annotation="javax.validation.constraints.NotNull"/>
      <constraint annotation="whatever.CustomValidation"/>
    </getter>
    

  </bean>

</constraint-mappings>

The only problem is, that it kinda does not work. In spring, with it's default autoconfigured Validator via LocalValidatorFactoryBean.

Validation with custom constraints declared via service loader works everywhere if constraint is specified via annotation. This xml-baxed stuff also works, but ONLY for built-in constraints, custom one are not found.

If I put breakpoint into ServiceLoader, then every call to it WILL discover mine custom validators. If it go through LocalValidatorFactoryBean initialization, I eventually got into org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper#registerCustomConstraintValidators, where I can see my ConstraintValidators discovered as well! But when it comes to validation itself, they are allegedly not declared. BUT! If I have annotation, ConstraintValidators, xml declarations, and ServiceLoader config file in 1 module, it all works! If I take just annotation, ConstraintValidators to another module, ONLY the xml-based annotation is broken. Location of ServiceLoader config file is irrelevant. No java 9 modules in action, afaik, but it would be weird, that it would affect just xml config based logic.

QUESTION:

Hibernate Validator internals are exceptionally complex. Can someone advice where to look what could go wrong why ConstraintValidators are not available even though they were discovered during LocalValidatorFactoryBean initialization?


Solution

  • It was confirmed as a Hibernate Validator bug.

    https://hibernate.atlassian.net/browse/HV-1949