demo project link: https://github.com/mingchiuli/demo


public class AnnoValidator implements ConstraintValidator<Anno, Pojo>  {

    @Resource
    private TestComponent testComponent;

    @Override
    public boolean isValid(Pojo value, ConstraintValidatorContext context) {
        testComponent.call();
        return true;
    }
}

In Spring boot 3.3.6, I found if I injected a component in a implement Class of ConstraintValidator in JVM mode, it worked normal:

(console output:)

123
test

But It would generated a NullPointerExeception in GraalVM's native-image :

2024-12-12T12:46:54.279+08:00 ERROR 36733 --- [demo] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: jakarta.validation.ValidationException: HV000028: Unexpected exception during isValid call.] with root cause

java.lang.NullPointerException: null
    at com.example.demo.pkg.AnnoValidator.isValid(AnnoValidator.java:14) ~[demo:na]
    at com.example.demo.pkg.AnnoValidator.isValid(AnnoValidator.java:7) ~[demo:na]

It seems the TestComponent can't be injected in native-image mode

Comment From: snicoll

@mingchiuli thanks for the report and the reproducer. ConstraintValidator is an hibernate entity that is instantiated on demand from Hibernate Validator. As it's not discovered by Spring AOT, we can't detect the use of @Resource and generate the appropriate code so that it works in a native image.

Adding hints won't matter as the bean post processor that's responsible for this is not active when running in a native image. We'll have to figure out what to do for this use case.

Comment From: snicoll

In the meantime, please move the dependency to the constructor so that we can process the type as expected, something like:

public class AnnoValidator implements ConstraintValidator<Anno, Pojo> {

    private final TestComponent testComponent;

    public AnnoValidator(TestComponent testComponent) {
        this.testComponent = testComponent;
    }

    ...
}