MethodValidationInterceptor excludes FactoryBean metadata methods

Issue: SPR-17374

(cherry picked from commit 5f2d47a17e)
This commit is contained in:
Juergen Hoeller
2018-10-14 21:07:56 +02:00
parent 6c9c8efc38
commit ebe3c270cb
3 changed files with 90 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -28,6 +28,8 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.validator.HibernateValidator; import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.core.BridgeMethodResolver; import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@@ -112,6 +114,11 @@ public class MethodValidationInterceptor implements MethodInterceptor {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object invoke(MethodInvocation invocation) throws Throwable { public Object invoke(MethodInvocation invocation) throws Throwable {
// Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
return invocation.proceed();
}
Class<?>[] groups = determineValidationGroups(invocation); Class<?>[] groups = determineValidationGroups(invocation);
if (forExecutablesMethod != null) { if (forExecutablesMethod != null) {
@@ -162,6 +169,12 @@ public class MethodValidationInterceptor implements MethodInterceptor {
} }
} }
private boolean isFactoryBeanMetadataMethod(Method method) {
Class<?> clazz = method.getDeclaringClass();
return ((clazz == FactoryBean.class || clazz == SmartFactoryBean.class) &&
!method.getName().equals("getObject"));
}
/** /**
* Determine the validation groups to validate against for the given method invocation. * Determine the validation groups to validate against for the given method invocation.
* <p>Default are the validation groups as specified in the {@link Validated} annotation * <p>Default are the validation groups as specified in the {@link Validated} annotation

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -122,8 +123,8 @@ public class MethodValidationTests {
@Test @Test
public void testLazyValidatorForMethodValidation() { public void testLazyValidatorForMethodValidation() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class); LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class);
ctx.getBean(MyValidInterface.class).myValidMethod("value", 5); ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
} }
@@ -146,6 +147,40 @@ public class MethodValidationTests {
} }
@MyStereotype
public static class MyValidFactoryBean implements FactoryBean<String>, MyValidInterface<String> {
@Override
public String getObject() {
return null;
}
@Override
public Class<?> getObjectType() {
return String.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public Object myValidMethod(String arg1, int arg2) {
return (arg2 == 0 ? null : "value");
}
@Override
public void myValidAsyncMethod(String arg1, int arg2) {
}
@Override
public String myGenericMethod(String value) {
return value;
}
}
public interface MyValidInterface<T> { public interface MyValidInterface<T> {
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2); @NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -49,7 +50,6 @@ import static org.junit.Assert.*;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 4.1 * @since 4.1
*/ */
@SuppressWarnings("rawtypes")
public class MethodValidationTests { public class MethodValidationTests {
@Test @Test
@@ -74,7 +74,6 @@ public class MethodValidationTests {
ac.close(); ac.close();
} }
@SuppressWarnings("unchecked")
private void doTestProxyValidation(MyValidInterface proxy) { private void doTestProxyValidation(MyValidInterface proxy) {
assertNotNull(proxy.myValidMethod("value", 5)); assertNotNull(proxy.myValidMethod("value", 5));
try { try {
@@ -128,8 +127,8 @@ public class MethodValidationTests {
@Test @Test
public void testLazyValidatorForMethodValidation() { public void testLazyValidatorForMethodValidation() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class); LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class);
ctx.getBean(MyValidInterface.class).myValidMethod("value", 5); ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
} }
@@ -152,6 +151,40 @@ public class MethodValidationTests {
} }
@MyStereotype
public static class MyValidFactoryBean implements FactoryBean<String>, MyValidInterface<String> {
@Override
public String getObject() {
return null;
}
@Override
public Class<?> getObjectType() {
return String.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public Object myValidMethod(String arg1, int arg2) {
return (arg2 == 0 ? null : "value");
}
@Override
public void myValidAsyncMethod(String arg1, int arg2) {
}
@Override
public String myGenericMethod(String value) {
return value;
}
}
public interface MyValidInterface<T> { public interface MyValidInterface<T> {
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2); @NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);