Skip to content

Commit 54004e0

Browse files
committed
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
1 parent 69ec437 commit 54004e0

File tree

128 files changed

+300
-26732
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+300
-26732
lines changed

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

Lines changed: 28 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
import java.lang.reflect.Proxy;
2525
import java.util.Arrays;
2626
import java.util.HashMap;
27+
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Properties;
2930
import javax.validation.Configuration;
3031
import javax.validation.ConstraintValidatorFactory;
3132
import javax.validation.MessageInterpolator;
33+
import javax.validation.ParameterNameProvider;
3234
import javax.validation.TraversableResolver;
3335
import javax.validation.Validation;
3436
import javax.validation.ValidationProviderResolver;
@@ -66,14 +68,8 @@
6668
* you will almost always use the default Validator anyway. This can also be injected directly
6769
* into any target dependency of type {@link org.springframework.validation.Validator}!
6870
*
69-
* <p><b>As of Spring 4.0, this class supports Bean Validation 1.0 and 1.1, with special support
70-
* for Hibernate Validator 4.3 and 5.x</b> (see {@link #setValidationMessageSource}).
71-
*
72-
* <p>Note that Bean Validation 1.1's {@code #forExecutables} method isn't supported: We do not
73-
* expect that method to be called by application code; consider {@link MethodValidationInterceptor}
74-
* instead. If you really need programmatic {@code #forExecutables} access, inject this class as
75-
* a {@link ValidatorFactory} and call {@link #getValidator()} on it, then {@code #forExecutables}
76-
* on the returned native {@link Validator} reference instead of directly on this class.
71+
* <p><b>As of Spring 5.0, this class requires Bean Validation 1.1, with special support
72+
* for Hibernate Validator 5.x</b> (see {@link #setValidationMessageSource}).
7773
*
7874
* <p>This class is also being used by Spring's MVC configuration namespace, in case of the
7975
* {@code javax.validation} API being present but no explicit Validator having been configured.
@@ -88,10 +84,6 @@
8884
public class LocalValidatorFactoryBean extends SpringValidatorAdapter
8985
implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
9086

91-
// Bean Validation 1.1 close() method available?
92-
private static final Method closeMethod = ClassUtils.getMethodIfAvailable(ValidatorFactory.class, "close");
93-
94-
9587
@SuppressWarnings("rawtypes")
9688
private Class providerClass;
9789

@@ -305,55 +297,23 @@ public void afterPropertiesSet() {
305297
}
306298

307299
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
308-
try {
309-
Class<?> parameterNameProviderClass =
310-
ClassUtils.forName("javax.validation.ParameterNameProvider", getClass().getClassLoader());
311-
Method parameterNameProviderMethod =
312-
Configuration.class.getMethod("parameterNameProvider", parameterNameProviderClass);
313-
final Object defaultProvider = ReflectionUtils.invokeMethod(
314-
Configuration.class.getMethod("getDefaultParameterNameProvider"), configuration);
315-
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
316-
Object parameterNameProvider = Proxy.newProxyInstance(getClass().getClassLoader(),
317-
new Class<?>[] {parameterNameProviderClass}, new InvocationHandler() {
318-
@Override
319-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
320-
if (method.getName().equals("getParameterNames")) {
321-
String[] result = null;
322-
if (args[0] instanceof Constructor) {
323-
result = discoverer.getParameterNames((Constructor<?>) args[0]);
324-
}
325-
else if (args[0] instanceof Method) {
326-
result = discoverer.getParameterNames((Method) args[0]);
327-
}
328-
if (result != null) {
329-
return Arrays.asList(result);
330-
}
331-
else {
332-
try {
333-
return method.invoke(defaultProvider, args);
334-
}
335-
catch (InvocationTargetException ex) {
336-
throw ex.getTargetException();
337-
}
338-
}
339-
}
340-
else {
341-
// toString, equals, hashCode
342-
try {
343-
return method.invoke(this, args);
344-
}
345-
catch (InvocationTargetException ex) {
346-
throw ex.getTargetException();
347-
}
348-
}
349-
}
350-
});
351-
ReflectionUtils.invokeMethod(parameterNameProviderMethod, configuration, parameterNameProvider);
352-
353-
}
354-
catch (Exception ex) {
355-
// Bean Validation 1.1 API not available - simply not applying the ParameterNameDiscoverer
356-
}
300+
// TODO: inner class
301+
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
302+
final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider();
303+
configuration.parameterNameProvider(new ParameterNameProvider() {
304+
@Override
305+
public List<String> getParameterNames(Constructor<?> constructor) {
306+
String[] paramNames = discoverer.getParameterNames(constructor);
307+
return (paramNames != null ? Arrays.asList(paramNames) :
308+
defaultProvider.getParameterNames(constructor));
309+
}
310+
@Override
311+
public List<String> getParameterNames(Method method) {
312+
String[] paramNames = discoverer.getParameterNames(method);
313+
return (paramNames != null ? Arrays.asList(paramNames) :
314+
defaultProvider.getParameterNames(method));
315+
}
316+
});
357317
}
358318

359319
/**
@@ -397,9 +357,14 @@ public ConstraintValidatorFactory getConstraintValidatorFactory() {
397357
return this.validatorFactory.getConstraintValidatorFactory();
398358
}
399359

360+
@Override
361+
public ParameterNameProvider getParameterNameProvider() {
362+
return this.validatorFactory.getParameterNameProvider();
363+
}
364+
400365
public void close() {
401-
if (closeMethod != null && this.validatorFactory != null) {
402-
ReflectionUtils.invokeMethod(closeMethod, this.validatorFactory);
366+
if (this.validatorFactory != null) {
367+
this.validatorFactory.close();
403368
}
404369
}
405370

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

Lines changed: 31 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
2626

2727
import org.aopalliance.intercept.MethodInterceptor;
2828
import org.aopalliance.intercept.MethodInvocation;
29-
import org.hibernate.validator.HibernateValidator;
3029

3130
import org.springframework.core.BridgeMethodResolver;
3231
import org.springframework.core.annotation.AnnotationUtils;
@@ -48,9 +47,8 @@
4847
* at the type level of the containing target class, applying to all public service methods
4948
* of that class. By default, JSR-303 will validate against its default group only.
5049
*
51-
* <p>As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider
52-
* (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator
53-
* 4.3. The actual provider will be autodetected and automatically adapted.
50+
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider
51+
* (such as Hibernate Validator 5.x).
5452
*
5553
* @author Juergen Hoeller
5654
* @since 3.1
@@ -88,8 +86,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
8886
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
8987
*/
9088
public MethodValidationInterceptor() {
91-
this(forExecutablesMethod != null ? Validation.buildDefaultValidatorFactory() :
92-
HibernateValidatorDelegate.buildValidatorFactory());
89+
this(Validation.buildDefaultValidatorFactory());
9390
}
9491

9592
/**
@@ -114,43 +111,36 @@ public MethodValidationInterceptor(Validator validator) {
114111
public Object invoke(MethodInvocation invocation) throws Throwable {
115112
Class<?>[] groups = determineValidationGroups(invocation);
116113

117-
if (forExecutablesMethod != null) {
118-
// Standard Bean Validation 1.1 API
119-
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
120-
Method methodToValidate = invocation.getMethod();
121-
Set<ConstraintViolation<?>> result;
122-
123-
try {
124-
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
125-
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
126-
}
127-
catch (IllegalArgumentException ex) {
128-
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
129-
// Let's try to find the bridged method on the implementation class...
130-
methodToValidate = BridgeMethodResolver.findBridgedMethod(
131-
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
132-
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
133-
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
134-
}
135-
if (!result.isEmpty()) {
136-
throw new ConstraintViolationException(result);
137-
}
138-
139-
Object returnValue = invocation.proceed();
140-
141-
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
142-
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
143-
if (!result.isEmpty()) {
144-
throw new ConstraintViolationException(result);
145-
}
146-
147-
return returnValue;
114+
// Standard Bean Validation 1.1 API
115+
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
116+
Method methodToValidate = invocation.getMethod();
117+
Set<ConstraintViolation<?>> result;
118+
119+
try {
120+
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
121+
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
122+
}
123+
catch (IllegalArgumentException ex) {
124+
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
125+
// Let's try to find the bridged method on the implementation class...
126+
methodToValidate = BridgeMethodResolver.findBridgedMethod(
127+
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
128+
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
129+
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
130+
}
131+
if (!result.isEmpty()) {
132+
throw new ConstraintViolationException(result);
148133
}
149134

150-
else {
151-
// Hibernate Validator 4.3's native API
152-
return HibernateValidatorDelegate.invokeWithinValidation(invocation, this.validator, groups);
135+
Object returnValue = invocation.proceed();
136+
137+
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
138+
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
139+
if (!result.isEmpty()) {
140+
throw new ConstraintViolationException(result);
153141
}
142+
143+
return returnValue;
154144
}
155145

156146
/**
@@ -168,36 +158,4 @@ protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
168158
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
169159
}
170160

171-
172-
/**
173-
* Inner class to avoid a hard-coded Hibernate Validator 4.3 dependency.
174-
*/
175-
private static class HibernateValidatorDelegate {
176-
177-
public static ValidatorFactory buildValidatorFactory() {
178-
return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
179-
}
180-
181-
@SuppressWarnings("deprecation")
182-
public static Object invokeWithinValidation(MethodInvocation invocation, Validator validator, Class<?>[] groups)
183-
throws Throwable {
184-
185-
org.hibernate.validator.method.MethodValidator methodValidator =
186-
validator.unwrap(org.hibernate.validator.method.MethodValidator.class);
187-
Set<org.hibernate.validator.method.MethodConstraintViolation<Object>> result =
188-
methodValidator.validateAllParameters(
189-
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
190-
if (!result.isEmpty()) {
191-
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
192-
}
193-
Object returnValue = invocation.proceed();
194-
result = methodValidator.validateReturnValue(
195-
invocation.getThis(), invocation.getMethod(), returnValue, groups);
196-
if (!result.isEmpty()) {
197-
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
198-
}
199-
return returnValue;
200-
}
201-
}
202-
203161
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Set;
2525
import java.util.TreeMap;
2626
import javax.validation.ConstraintViolation;
27+
import javax.validation.executable.ExecutableValidator;
2728
import javax.validation.metadata.BeanDescriptor;
2829
import javax.validation.metadata.ConstraintDescriptor;
2930

@@ -299,6 +300,11 @@ public <T> T unwrap(Class<T> type) {
299300
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
300301
}
301302

303+
@Override
304+
public ExecutableValidator forExecutables() {
305+
return this.targetValidator.forExecutables();
306+
}
307+
302308

303309
/**
304310
* Wrapper for a String attribute which can be resolved via a {@code MessageSource},

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,10 +31,9 @@
3131
import static org.junit.Assert.*;
3232

3333
/**
34-
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
34+
* Tested against Hibernate Validator 5.x.
3535
*
3636
* @author Juergen Hoeller
37-
* @since 3.0
3837
*/
3938
public class BeanValidationPostProcessorTests {
4039

@@ -52,6 +51,7 @@ public void testNotNullConstraint() {
5251
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
5352
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
5453
}
54+
ac.close();
5555
}
5656

5757
@Test
@@ -63,6 +63,7 @@ public void testNotNullConstraintSatisfied() {
6363
bd.getPropertyValues().add("testBean", new TestBean());
6464
ac.registerBeanDefinition("bean", bd);
6565
ac.refresh();
66+
ac.close();
6667
}
6768

6869
@Test
@@ -74,6 +75,7 @@ public void testNotNullConstraintAfterInitialization() {
7475
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
7576
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
7677
ac.refresh();
78+
ac.close();
7779
}
7880

7981
@Test
@@ -92,6 +94,7 @@ public void testSizeConstraint() {
9294
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
9395
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
9496
}
97+
ac.close();
9598
}
9699

97100
@Test
@@ -103,6 +106,7 @@ public void testSizeConstraintSatisfied() {
103106
bd.getPropertyValues().add("stringValue", "ss");
104107
ac.registerBeanDefinition("bean", bd);
105108
ac.refresh();
109+
ac.close();
106110
}
107111

108112

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,11 +35,11 @@
3535
import static org.junit.Assert.*;
3636

3737
/**
38-
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
38+
* Tests against Hibernate Validator 5.x.
3939
*
4040
* @author Juergen Hoeller
41-
* @since 3.1
4241
*/
42+
@SuppressWarnings("rawtypes")
4343
public class MethodValidationTests {
4444

4545
@Test
@@ -65,6 +65,7 @@ public void testMethodValidationPostProcessor() {
6565
}
6666

6767

68+
@SuppressWarnings("unchecked")
6869
private void doTestProxyValidation(MyValidInterface proxy) {
6970
assertNotNull(proxy.myValidMethod("value", 5));
7071
try {

0 commit comments

Comments
 (0)