Browse Source

LocalValidatorFactoryBean properly supports unwrap at ValidatorFactory level

Also documents limitation for Bean Validation 2.0's getClockProvider() method.

Issue: SPR-15561
Issue: SPR-13482
pull/1284/merge
Juergen Hoeller 8 years ago
parent
commit
cb3d1befcd
  1. 34
      spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java
  2. 7
      spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
  3. 12
      spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java
  4. 17
      spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java

34
spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java

@ -30,6 +30,7 @@ import javax.validation.MessageInterpolator; @@ -30,6 +30,7 @@ import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.ValidationProviderResolver;
import javax.validation.Validator;
import javax.validation.ValidatorContext;
@ -64,8 +65,12 @@ import org.springframework.util.ReflectionUtils; @@ -64,8 +65,12 @@ import org.springframework.util.ReflectionUtils;
* you will almost always use the default Validator anyway. This can also be injected directly
* into any target dependency of type {@link org.springframework.validation.Validator}!
*
* <p><b>As of Spring 5.0, this class requires Bean Validation 1.1, with special support
* <p><b>As of Spring 5.0, this class requires Bean Validation 1.1+, with special support
* for Hibernate Validator 5.x</b> (see {@link #setValidationMessageSource}).
* This class is also runtime-compatible with Bean Validation 2.0 and Hibernate Validator 6.0,
* with one special note: If you'd like to call BV 2.0's {@code getClockProvider()} method,
* obtain the native {@code ValidatorFactory} through {@code #unwrap(ValidatorFactory.class)}
* and call the {@code getClockProvider()} method on the returned native reference there.
*
* <p>This class is also being used by Spring's MVC configuration namespace, in case of the
* {@code javax.validation} API being present but no explicit Validator having been configured.
@ -293,7 +298,6 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter @@ -293,7 +298,6 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
}
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
// TODO: inner class
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider();
configuration.parameterNameProvider(new ParameterNameProvider() {
@ -359,6 +363,32 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter @@ -359,6 +363,32 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
return this.validatorFactory.getParameterNameProvider();
}
// Bean Validation 2.0: currently not implemented here since it would imply
// a hard dependency on the new javax.validation.ClockProvider interface.
// To be resolved once Spring Framework requires Bean Validation 2.0+.
// Obtain the native ValidatorFactory through unwrap(ValidatorFactory.class)
// instead which will fully support a getClockProvider() call as well.
/*
@Override
public javax.validation.ClockProvider getClockProvider() {
Assert.notNull(this.validatorFactory, "No target ValidatorFactory set");
return this.validatorFactory.getClockProvider();
}
*/
@Override
public <T> T unwrap(Class<T> type) {
if (type == null || !ValidatorFactory.class.isAssignableFrom(type)) {
try {
return super.unwrap(type);
}
catch (ValidationException ex) {
// ignore - we'll try ValidatorFactory unwrapping next
}
}
return this.validatorFactory.unwrap(type);
}
public void close() {
if (this.validatorFactory != null) {
this.validatorFactory.close();

7
spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java

@ -40,13 +40,16 @@ import org.springframework.validation.ObjectError; @@ -40,13 +40,16 @@ import org.springframework.validation.ObjectError;
import org.springframework.validation.SmartValidator;
/**
* Adapter that takes a JSR-303 {@code javax.validator.Validator}
* and exposes it as a Spring {@link org.springframework.validation.Validator}
* Adapter that takes a JSR-303 {@code javax.validator.Validator} and
* exposes it as a Spring {@link org.springframework.validation.Validator}
* while also exposing the original JSR-303 Validator interface itself.
*
* <p>Can be used as a programmatic wrapper. Also serves as base class for
* {@link CustomValidatorBean} and {@link LocalValidatorFactoryBean}.
*
* <p>As of Spring Framework 5.0, this adapter is fully compatible with
* Bean Validation 1.1 as well as 2.0.
*
* @author Juergen Hoeller
* @since 3.0
*/

12
spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java

@ -27,6 +27,7 @@ import javax.validation.ConstraintValidator; @@ -27,6 +27,7 @@ import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
@ -51,8 +52,9 @@ import static org.junit.Assert.*; @@ -51,8 +52,9 @@ import static org.junit.Assert.*;
*/
public class SpringValidatorAdapterTests {
private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(
Validation.buildDefaultValidatorFactory().getValidator());
private final Validator nativeValidator = Validation.buildDefaultValidatorFactory().getValidator();
private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(nativeValidator);
private final StaticMessageSource messageSource = new StaticMessageSource();
@ -66,6 +68,12 @@ public class SpringValidatorAdapterTests { @@ -66,6 +68,12 @@ public class SpringValidatorAdapterTests {
}
@Test
public void testUnwrap() {
Validator nativeValidator = validatorAdapter.unwrap(Validator.class);
assertSame(this.nativeValidator, nativeValidator);
}
@Test // SPR-13406
public void testNoStringArgumentValue() {
TestBean testBean = new TestBean();

17
spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java

@ -33,9 +33,12 @@ import javax.validation.ConstraintValidatorContext; @@ -33,9 +33,12 @@ import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;
import javax.validation.Payload;
import javax.validation.Valid;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -75,6 +78,12 @@ public class ValidatorFactoryTests { @@ -75,6 +78,12 @@ public class ValidatorFactoryTests {
fail("Invalid constraint violation with path '" + path + "'");
}
}
Validator nativeValidator = validator.unwrap(Validator.class);
assertTrue(nativeValidator.getClass().getName().startsWith("org.hibernate"));
assertTrue(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory);
assertTrue(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory);
validator.destroy();
}
@ -96,6 +105,12 @@ public class ValidatorFactoryTests { @@ -96,6 +105,12 @@ public class ValidatorFactoryTests {
fail("Invalid constraint violation with path '" + path + "'");
}
}
Validator nativeValidator = validator.unwrap(Validator.class);
assertTrue(nativeValidator.getClass().getName().startsWith("org.hibernate"));
assertTrue(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory);
assertTrue(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory);
validator.destroy();
}
@ -465,7 +480,7 @@ public class ValidatorFactoryTests { @@ -465,7 +480,7 @@ public class ValidatorFactoryTests {
String message() default "Should not be X";
Class<?>[] groups() default { };
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

Loading…
Cancel
Save