Skip to content

Commit d1f42ac

Browse files
committed
Unwrap Validator proxy for access to forExecutables (if necessary)
Issue: SPR-15807
1 parent 17f42fc commit d1f42ac

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

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

+14-5
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-2017 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.
@@ -81,7 +81,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
8181
}
8282

8383

84-
private final Validator validator;
84+
private volatile Validator validator;
8585

8686

8787
/**
@@ -116,7 +116,18 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
116116

117117
if (forExecutablesMethod != null) {
118118
// Standard Bean Validation 1.1 API
119-
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
119+
Object execVal;
120+
try {
121+
execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
122+
}
123+
catch (AbstractMethodError err) {
124+
// Probably an adapter (maybe a lazy-init proxy) without BV 1.1 support
125+
Validator nativeValidator = this.validator.unwrap(Validator.class);
126+
execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, nativeValidator);
127+
// If successful, store native Validator for further use
128+
this.validator = nativeValidator;
129+
}
130+
120131
Method methodToValidate = invocation.getMethod();
121132
Set<ConstraintViolation<?>> result;
122133

@@ -137,13 +148,11 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
137148
}
138149

139150
Object returnValue = invocation.proceed();
140-
141151
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
142152
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
143153
if (!result.isEmpty()) {
144154
throw new ConstraintViolationException(result);
145155
}
146-
147156
return returnValue;
148157
}
149158

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

+25-2
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-2017 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.
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.RetentionPolicy;
21+
import javax.validation.Validator;
2122
import javax.validation.constraints.Max;
2223
import javax.validation.constraints.NotNull;
2324
import javax.validation.groups.Default;
@@ -26,6 +27,10 @@
2627

2728
import org.springframework.aop.framework.ProxyFactory;
2829
import org.springframework.beans.MutablePropertyValues;
30+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
31+
import org.springframework.context.annotation.Bean;
32+
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.context.annotation.Lazy;
2934
import org.springframework.context.support.StaticApplicationContext;
3035
import org.springframework.scheduling.annotation.Async;
3136
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
@@ -64,7 +69,6 @@ public void testMethodValidationPostProcessor() {
6469
ac.close();
6570
}
6671

67-
6872
private void doTestProxyValidation(MyValidInterface proxy) {
6973
assertNotNull(proxy.myValidMethod("value", 5));
7074
try {
@@ -115,6 +119,13 @@ private void doTestProxyValidation(MyValidInterface proxy) {
115119
}
116120
}
117121

122+
@Test
123+
public void testLazyValidatorForMethodValidation() {
124+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
125+
LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class);
126+
ctx.getBean(MyValidInterface.class).myValidMethod("value", 5);
127+
}
128+
118129

119130
@MyStereotype
120131
public static class MyValidBean implements MyValidInterface<String> {
@@ -165,4 +176,16 @@ public interface OtherGroup {
165176
public @interface MyValid {
166177
}
167178

179+
180+
@Configuration
181+
public static class LazyMethodValidationConfig {
182+
183+
@Bean
184+
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
185+
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
186+
postProcessor.setValidator(validator);
187+
return postProcessor;
188+
}
189+
}
190+
168191
}

spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java

+26-2
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-2017 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.
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.RetentionPolicy;
21+
import javax.validation.Validator;
2122
import javax.validation.constraints.Max;
2223
import javax.validation.constraints.NotNull;
2324
import javax.validation.groups.Default;
@@ -26,11 +27,16 @@
2627

2728
import org.springframework.aop.framework.ProxyFactory;
2829
import org.springframework.beans.MutablePropertyValues;
30+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
31+
import org.springframework.context.annotation.Bean;
32+
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.context.annotation.Lazy;
2934
import org.springframework.context.support.StaticApplicationContext;
3035
import org.springframework.scheduling.annotation.Async;
3136
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
3237
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
3338
import org.springframework.validation.annotation.Validated;
39+
import org.springframework.validation.beanvalidation.CustomValidatorBean;
3440
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
3541
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
3642

@@ -68,7 +74,6 @@ public void testMethodValidationPostProcessor() {
6874
ac.close();
6975
}
7076

71-
7277
@SuppressWarnings("unchecked")
7378
private void doTestProxyValidation(MyValidInterface proxy) {
7479
assertNotNull(proxy.myValidMethod("value", 5));
@@ -120,6 +125,13 @@ private void doTestProxyValidation(MyValidInterface proxy) {
120125
}
121126
}
122127

128+
@Test
129+
public void testLazyValidatorForMethodValidation() {
130+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
131+
LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class);
132+
ctx.getBean(MyValidInterface.class).myValidMethod("value", 5);
133+
}
134+
123135

124136
@MyStereotype
125137
public static class MyValidBean implements MyValidInterface<String> {
@@ -170,4 +182,16 @@ public interface OtherGroup {
170182
public @interface MyValid {
171183
}
172184

185+
186+
@Configuration
187+
public static class LazyMethodValidationConfig {
188+
189+
@Bean
190+
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
191+
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
192+
postProcessor.setValidator(validator);
193+
return postProcessor;
194+
}
195+
}
196+
173197
}

0 commit comments

Comments
 (0)