@ -18,7 +18,9 @@ package org.springframework.boot.autoconfigure.validation;
@@ -18,7 +18,9 @@ package org.springframework.boot.autoconfigure.validation;
import java.util.HashMap ;
import jakarta.validation.Validator ;
import jakarta.validation.constraints.Min ;
import org.hibernate.validator.HibernateValidator ;
import org.junit.jupiter.api.Test ;
import org.springframework.boot.test.context.FilteredClassLoader ;
@ -27,10 +29,13 @@ import org.springframework.context.ApplicationContext;
@@ -27,10 +29,13 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean ;
import org.springframework.context.annotation.Configuration ;
import org.springframework.core.io.ClassPathResource ;
import org.springframework.validation.Errors ;
import org.springframework.validation.MapBindingResult ;
import org.springframework.validation.SmartValidator ;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatRuntimeException ;
import static org.mockito.ArgumentMatchers.any ;
import static org.mockito.BDDMockito.then ;
import static org.mockito.Mockito.mock ;
@ -91,6 +96,30 @@ class ValidatorAdapterTests {
@@ -91,6 +96,30 @@ class ValidatorAdapterTests {
. run ( ( context ) - > ValidatorAdapter . get ( context , null ) ) ;
}
@Test
void unwrapToJakartaValidatorShouldReturnJakartaValidator ( ) {
this . contextRunner . withUserConfiguration ( LocalValidatorFactoryBeanConfig . class ) . run ( ( context ) - > {
ValidatorAdapter wrapper = context . getBean ( ValidatorAdapter . class ) ;
assertThat ( wrapper . unwrap ( Validator . class ) ) . isInstanceOf ( Validator . class ) ;
} ) ;
}
@Test
void whenJakartaValidatorIsWrappedMultipleTimesUnwrapToJakartaValidatorShouldReturnJakartaValidator ( ) {
this . contextRunner . withUserConfiguration ( DoubleWrappedConfig . class ) . run ( ( context ) - > {
ValidatorAdapter wrapper = context . getBean ( ValidatorAdapter . class ) ;
assertThat ( wrapper . unwrap ( Validator . class ) ) . isInstanceOf ( Validator . class ) ;
} ) ;
}
@Test
void unwrapToUnsupportedTypeShouldThrow ( ) {
this . contextRunner . withUserConfiguration ( LocalValidatorFactoryBeanConfig . class ) . run ( ( context ) - > {
ValidatorAdapter wrapper = context . getBean ( ValidatorAdapter . class ) ;
assertThatRuntimeException ( ) . isThrownBy ( ( ) - > wrapper . unwrap ( HibernateValidator . class ) ) ;
} ) ;
}
@Configuration ( proxyBeanMethods = false )
static class LocalValidatorFactoryBeanConfig {
@ -106,6 +135,55 @@ class ValidatorAdapterTests {
@@ -106,6 +135,55 @@ class ValidatorAdapterTests {
}
@Configuration ( proxyBeanMethods = false )
static class DoubleWrappedConfig {
@Bean
LocalValidatorFactoryBean validator ( ) {
return new LocalValidatorFactoryBean ( ) ;
}
@Bean
ValidatorAdapter wrapper ( LocalValidatorFactoryBean validator ) {
return new ValidatorAdapter ( new Wrapper ( validator ) , true ) ;
}
static class Wrapper implements SmartValidator {
private final SmartValidator delegate ;
Wrapper ( SmartValidator delegate ) {
this . delegate = delegate ;
}
@Override
public boolean supports ( Class < ? > clazz ) {
return this . delegate . supports ( clazz ) ;
}
@Override
public void validate ( Object target , Errors errors ) {
this . delegate . validate ( target , errors ) ;
}
@Override
public void validate ( Object target , Errors errors , Object . . . validationHints ) {
this . delegate . validate ( target , errors , validationHints ) ;
}
@Override
@SuppressWarnings ( "unchecked" )
public < T > T unwrap ( Class < T > type ) {
if ( type . isInstance ( this . delegate ) ) {
return ( T ) this . delegate ;
}
return this . delegate . unwrap ( type ) ;
}
}
}
@Configuration ( proxyBeanMethods = false )
static class NonManagedBeanConfig {