Browse Source

Fix MVC and WebFlux validator creation in a native image

Following modularization, a presence check for ValidatorAdapter was
needed in the MVC and WebFlux auto-configuratiomn when creating
their Validators. Runtime hints to allow this check to work in a
native image were not added at the same time, resulting in the
class appearing to be absent. This caused message interpolation
for constraint violations to fail as newly created Validator was
being used which lacked the necessary MessageInterpolator
configuration.

This commit adds reflection hints for ValidatorAdapter, allowing
re-use of the context's main validator as the MVC and WebFlux
validators.

Fixes gh-48828
pull/48875/head
Andy Wilkinson 2 weeks ago
parent
commit
625571c3d1
  1. 14
      module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java
  2. 10
      module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java
  3. 14
      module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java
  4. 10
      module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java

14
module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java

@ -25,6 +25,9 @@ import org.apache.commons.logging.LogFactory; @@ -25,6 +25,9 @@ import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Mono;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@ -308,6 +311,7 @@ public final class WebFluxAutoConfiguration { @@ -308,6 +311,7 @@ public final class WebFluxAutoConfiguration {
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, ServerProperties.class })
@ImportRuntimeHints(WebFluxValidatorRuntimeHints.class)
static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
private final WebFluxProperties webFluxProperties;
@ -452,4 +456,14 @@ public final class WebFluxAutoConfiguration { @@ -452,4 +456,14 @@ public final class WebFluxAutoConfiguration {
}
static class WebFluxValidatorRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection()
.registerType(TypeReference.of("org.springframework.boot.validation.autoconfigure.ValidatorAdapter"));
}
}
}

10
module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java

@ -46,6 +46,8 @@ import org.junit.jupiter.params.provider.ValueSource; @@ -46,6 +46,8 @@ import org.junit.jupiter.params.provider.ValueSource;
import reactor.core.publisher.Mono;
import org.springframework.aop.support.AopUtils;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.http.codec.CodecCustomizer;
@ -59,6 +61,7 @@ import org.springframework.boot.web.context.reactive.ReactiveWebApplicationConte @@ -59,6 +61,7 @@ import org.springframework.boot.web.context.reactive.ReactiveWebApplicationConte
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration.WebFluxConfig;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration.WebFluxValidatorRuntimeHints;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;
import org.springframework.boot.webflux.filter.OrderedHiddenHttpMethodFilter;
@ -907,6 +910,13 @@ class WebFluxAutoConfigurationTests { @@ -907,6 +910,13 @@ class WebFluxAutoConfigurationTests {
});
}
@Test
void registersRuntimeHintsForValidatorCreation() {
RuntimeHints hints = new RuntimeHints();
new WebFluxValidatorRuntimeHints().registerHints(hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(ValidatorAdapter.class)).accepts(hints);
}
private ContextConsumer<ReactiveWebApplicationContext> assertExchangeWithSession(
Consumer<MockServerWebExchange> exchange) {
return (context) -> {

14
module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java

@ -28,6 +28,9 @@ import org.apache.commons.logging.Log; @@ -28,6 +28,9 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -435,6 +438,7 @@ public final class WebMvcAutoConfiguration { @@ -435,6 +438,7 @@ public final class WebMvcAutoConfiguration {
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
@ImportRuntimeHints(MvcValidatorRuntimeHints.class)
static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private final Resources resourceProperties;
@ -724,4 +728,14 @@ public final class WebMvcAutoConfiguration { @@ -724,4 +728,14 @@ public final class WebMvcAutoConfiguration {
}
static class MvcValidatorRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection()
.registerType(TypeReference.of("org.springframework.boot.validation.autoconfigure.ValidatorAdapter"));
}
}
}

10
module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java

@ -45,6 +45,8 @@ import org.junit.jupiter.api.Test; @@ -45,6 +45,8 @@ import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.aop.support.AopUtils;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
@ -64,6 +66,7 @@ import org.springframework.boot.web.server.servlet.ServletWebServerFactory; @@ -64,6 +66,7 @@ import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration.MvcValidatorRuntimeHints;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;
@ -1137,6 +1140,13 @@ class WebMvcAutoConfigurationTests { @@ -1137,6 +1140,13 @@ class WebMvcAutoConfigurationTests {
});
}
@Test
void registersRuntimeHintsForValidatorCreation() {
RuntimeHints hints = new RuntimeHints();
new MvcValidatorRuntimeHints().registerHints(hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection().onType(ValidatorAdapter.class)).accepts(hints);
}
private void assertResourceHttpRequestHandler(AssertableWebApplicationContext context,
Consumer<ResourceHttpRequestHandler> handlerConsumer) {
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));

Loading…
Cancel
Save