diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java index bbcf92ea9e..42427f4c83 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java @@ -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"); * 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.hibernate.validator.HibernateValidator; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.SmartFactoryBean; import org.springframework.core.BridgeMethodResolver; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ClassUtils; @@ -112,6 +114,11 @@ public class MethodValidationInterceptor implements MethodInterceptor { @Override @SuppressWarnings("unchecked") 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); 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. *

Default are the validation groups as specified in the {@link Validated} annotation diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java index a6af80e722..63746bbbf5 100644 --- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java @@ -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"); * 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.beans.MutablePropertyValues; +import org.springframework.beans.factory.FactoryBean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -122,8 +123,8 @@ public class MethodValidationTests { @Test public void testLazyValidatorForMethodValidation() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class); - ctx.getBean(MyValidInterface.class).myValidMethod("value", 5); + LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class); + 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, MyValidInterface { + + @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 { @NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2); diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java index 14135a03c7..4a7454b4fb 100644 --- a/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java +++ b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java @@ -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"); * 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.beans.MutablePropertyValues; +import org.springframework.beans.factory.FactoryBean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -49,7 +50,6 @@ import static org.junit.Assert.*; * @author Juergen Hoeller * @since 4.1 */ -@SuppressWarnings("rawtypes") public class MethodValidationTests { @Test @@ -74,7 +74,6 @@ public class MethodValidationTests { ac.close(); } - @SuppressWarnings("unchecked") private void doTestProxyValidation(MyValidInterface proxy) { assertNotNull(proxy.myValidMethod("value", 5)); try { @@ -128,8 +127,8 @@ public class MethodValidationTests { @Test public void testLazyValidatorForMethodValidation() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class); - ctx.getBean(MyValidInterface.class).myValidMethod("value", 5); + LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class); + 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, MyValidInterface { + + @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 { @NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);