Upgrade to JPA 2.1+ and Bean Validation 1.1+; remove native support for Hibernate 3.6 and 4.x
Issue: SPR-13481 Issue: SPR-13827
This commit is contained in:
@@ -24,11 +24,13 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.validation.Configuration;
|
||||
import javax.validation.ConstraintValidatorFactory;
|
||||
import javax.validation.MessageInterpolator;
|
||||
import javax.validation.ParameterNameProvider;
|
||||
import javax.validation.TraversableResolver;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.ValidationProviderResolver;
|
||||
@@ -66,14 +68,8 @@ 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 4.0, this class supports Bean Validation 1.0 and 1.1, with special support
|
||||
* for Hibernate Validator 4.3 and 5.x</b> (see {@link #setValidationMessageSource}).
|
||||
*
|
||||
* <p>Note that Bean Validation 1.1's {@code #forExecutables} method isn't supported: We do not
|
||||
* expect that method to be called by application code; consider {@link MethodValidationInterceptor}
|
||||
* instead. If you really need programmatic {@code #forExecutables} access, inject this class as
|
||||
* a {@link ValidatorFactory} and call {@link #getValidator()} on it, then {@code #forExecutables}
|
||||
* on the returned native {@link Validator} reference instead of directly on this class.
|
||||
* <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}).
|
||||
*
|
||||
* <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.
|
||||
@@ -88,10 +84,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
|
||||
|
||||
// Bean Validation 1.1 close() method available?
|
||||
private static final Method closeMethod = ClassUtils.getMethodIfAvailable(ValidatorFactory.class, "close");
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Class providerClass;
|
||||
|
||||
@@ -305,55 +297,23 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
}
|
||||
|
||||
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
|
||||
try {
|
||||
Class<?> parameterNameProviderClass =
|
||||
ClassUtils.forName("javax.validation.ParameterNameProvider", getClass().getClassLoader());
|
||||
Method parameterNameProviderMethod =
|
||||
Configuration.class.getMethod("parameterNameProvider", parameterNameProviderClass);
|
||||
final Object defaultProvider = ReflectionUtils.invokeMethod(
|
||||
Configuration.class.getMethod("getDefaultParameterNameProvider"), configuration);
|
||||
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
|
||||
Object parameterNameProvider = Proxy.newProxyInstance(getClass().getClassLoader(),
|
||||
new Class<?>[] {parameterNameProviderClass}, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("getParameterNames")) {
|
||||
String[] result = null;
|
||||
if (args[0] instanceof Constructor) {
|
||||
result = discoverer.getParameterNames((Constructor<?>) args[0]);
|
||||
}
|
||||
else if (args[0] instanceof Method) {
|
||||
result = discoverer.getParameterNames((Method) args[0]);
|
||||
}
|
||||
if (result != null) {
|
||||
return Arrays.asList(result);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return method.invoke(defaultProvider, args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// toString, equals, hashCode
|
||||
try {
|
||||
return method.invoke(this, args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ReflectionUtils.invokeMethod(parameterNameProviderMethod, configuration, parameterNameProvider);
|
||||
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Bean Validation 1.1 API not available - simply not applying the ParameterNameDiscoverer
|
||||
}
|
||||
// TODO: inner class
|
||||
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
|
||||
final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider();
|
||||
configuration.parameterNameProvider(new ParameterNameProvider() {
|
||||
@Override
|
||||
public List<String> getParameterNames(Constructor<?> constructor) {
|
||||
String[] paramNames = discoverer.getParameterNames(constructor);
|
||||
return (paramNames != null ? Arrays.asList(paramNames) :
|
||||
defaultProvider.getParameterNames(constructor));
|
||||
}
|
||||
@Override
|
||||
public List<String> getParameterNames(Method method) {
|
||||
String[] paramNames = discoverer.getParameterNames(method);
|
||||
return (paramNames != null ? Arrays.asList(paramNames) :
|
||||
defaultProvider.getParameterNames(method));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,9 +357,14 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return this.validatorFactory.getConstraintValidatorFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterNameProvider getParameterNameProvider() {
|
||||
return this.validatorFactory.getParameterNameProvider();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (closeMethod != null && this.validatorFactory != null) {
|
||||
ReflectionUtils.invokeMethod(closeMethod, this.validatorFactory);
|
||||
if (this.validatorFactory != null) {
|
||||
this.validatorFactory.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,6 @@ import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -48,9 +47,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
* at the type level of the containing target class, applying to all public service methods
|
||||
* of that class. By default, JSR-303 will validate against its default group only.
|
||||
*
|
||||
* <p>As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider
|
||||
* (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator
|
||||
* 4.3. The actual provider will be autodetected and automatically adapted.
|
||||
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider
|
||||
* (such as Hibernate Validator 5.x).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
@@ -88,8 +86,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
|
||||
*/
|
||||
public MethodValidationInterceptor() {
|
||||
this(forExecutablesMethod != null ? Validation.buildDefaultValidatorFactory() :
|
||||
HibernateValidatorDelegate.buildValidatorFactory());
|
||||
this(Validation.buildDefaultValidatorFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,43 +111,36 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Class<?>[] groups = determineValidationGroups(invocation);
|
||||
|
||||
if (forExecutablesMethod != null) {
|
||||
// Standard Bean Validation 1.1 API
|
||||
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
|
||||
Method methodToValidate = invocation.getMethod();
|
||||
Set<ConstraintViolation<?>> result;
|
||||
// Standard Bean Validation 1.1 API
|
||||
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
|
||||
Method methodToValidate = invocation.getMethod();
|
||||
Set<ConstraintViolation<?>> result;
|
||||
|
||||
try {
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
|
||||
// Let's try to find the bridged method on the implementation class...
|
||||
methodToValidate = BridgeMethodResolver.findBridgedMethod(
|
||||
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
throw new ConstraintViolationException(result);
|
||||
}
|
||||
|
||||
Object returnValue = invocation.proceed();
|
||||
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new ConstraintViolationException(result);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
try {
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
|
||||
// Let's try to find the bridged method on the implementation class...
|
||||
methodToValidate = BridgeMethodResolver.findBridgedMethod(
|
||||
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
throw new ConstraintViolationException(result);
|
||||
}
|
||||
|
||||
else {
|
||||
// Hibernate Validator 4.3's native API
|
||||
return HibernateValidatorDelegate.invokeWithinValidation(invocation, this.validator, groups);
|
||||
Object returnValue = invocation.proceed();
|
||||
|
||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
|
||||
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new ConstraintViolationException(result);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,36 +158,4 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard-coded Hibernate Validator 4.3 dependency.
|
||||
*/
|
||||
private static class HibernateValidatorDelegate {
|
||||
|
||||
public static ValidatorFactory buildValidatorFactory() {
|
||||
return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Object invokeWithinValidation(MethodInvocation invocation, Validator validator, Class<?>[] groups)
|
||||
throws Throwable {
|
||||
|
||||
org.hibernate.validator.method.MethodValidator methodValidator =
|
||||
validator.unwrap(org.hibernate.validator.method.MethodValidator.class);
|
||||
Set<org.hibernate.validator.method.MethodConstraintViolation<Object>> result =
|
||||
methodValidator.validateAllParameters(
|
||||
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
|
||||
}
|
||||
Object returnValue = invocation.proceed();
|
||||
result = methodValidator.validateReturnValue(
|
||||
invocation.getThis(), invocation.getMethod(), returnValue, groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
import javax.validation.metadata.BeanDescriptor;
|
||||
import javax.validation.metadata.ConstraintDescriptor;
|
||||
|
||||
@@ -299,6 +300,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutableValidator forExecutables() {
|
||||
return this.targetValidator.forExecutables();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for a String attribute which can be resolved via a {@code MessageSource},
|
||||
|
||||
Reference in New Issue
Block a user