diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java index 76c295490e..54467cd3ea 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java +++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java @@ -41,8 +41,8 @@ import static org.springframework.beans.PropertyDescriptorUtils.*; /** * Decorator for a standard {@link BeanInfo} object, e.g. as created by - * {@link Introspector#getBeanInfo(Class)}, designed to discover and register non-void - * returning setter methods. For example: + * {@link Introspector#getBeanInfo(Class)}, designed to discover and register static + * and/or non-void returning setter methods. For example: *
{@code
  * public class Bean {
  *     private Foo foo;
@@ -102,37 +102,40 @@ class ExtendedBeanInfo implements BeanInfo {
 					new SimpleNonIndexedPropertyDescriptor(pd));
 		}
 
-		for (Method method : findNonVoidWriteMethods(delegate.getMethodDescriptors())) {
-			handleNonVoidWriteMethod(method);
+		for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
+			handleCandidateWriteMethod(method);
 		}
 	}
 
 
-	private List findNonVoidWriteMethods(MethodDescriptor[] methodDescriptors) {
+	private List findCandidateWriteMethods(MethodDescriptor[] methodDescriptors) {
 		List matches = new ArrayList();
 		for (MethodDescriptor methodDescriptor : methodDescriptors) {
 			Method method = methodDescriptor.getMethod();
-			if (isNonVoidWriteMethod(method)) {
+			if (isCandidateWriteMethod(method)) {
 				matches.add(method);
 			}
 		}
 		return matches;
 	}
 
-	public static boolean isNonVoidWriteMethod(Method method) {
+	public static boolean isCandidateWriteMethod(Method method) {
 		String methodName = method.getName();
 		Class[] parameterTypes = method.getParameterTypes();
 		int nParams = parameterTypes.length;
 		if (methodName.length() > 3 && methodName.startsWith("set") &&
 				Modifier.isPublic(method.getModifiers()) &&
-				!void.class.isAssignableFrom(method.getReturnType()) &&
+				(
+						!void.class.isAssignableFrom(method.getReturnType()) ||
+						Modifier.isStatic(method.getModifiers())
+				) &&
 				(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) {
 			return true;
 		}
 		return false;
 	}
 
-	private void handleNonVoidWriteMethod(Method method) throws IntrospectionException {
+	private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
 		int nParams = method.getParameterTypes().length;
 		String propertyName = propertyNameFor(method);
 		Class propertyType = method.getParameterTypes()[nParams-1];
diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java
index 7e46211922..183ffe4e2a 100644
--- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java
@@ -51,7 +51,7 @@ public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
 	 */
 	private boolean supports(Class beanClass) {
 		for (Method method : beanClass.getMethods()) {
-			if (ExtendedBeanInfo.isNonVoidWriteMethod(method)) {
+			if (ExtendedBeanInfo.isCandidateWriteMethod(method)) {
 				return true;
 			}
 		}
diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java
index 7da9710417..9ea8c569e7 100644
--- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java
@@ -1550,6 +1550,24 @@ public final class BeanWrapperTests {
 		assertEquals(TestEnum.TEST_VALUE, consumer.getEnumValue());
 	}
 
+	@Test
+	public void cornerSpr10115() {
+		Spr10115Bean foo = new Spr10115Bean();
+		BeanWrapperImpl bwi = new BeanWrapperImpl();
+		bwi.setWrappedInstance(foo);
+		bwi.setPropertyValue("prop1", "val1");
+		assertEquals("val1", Spr10115Bean.prop1);
+	}
+
+
+	static class Spr10115Bean {
+		private static String prop1;
+
+		public static void setProp1(String prop1) {
+			Spr10115Bean.prop1 = prop1;
+		}
+	}
+
 
 	private static class Foo {
 
diff --git a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java
index fd53b58af7..44062a9107 100644
--- a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java
@@ -946,4 +946,28 @@ public class ExtendedBeanInfoTests {
 			assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
 		}
 	}
+
+	@Test
+	public void shouldSupportStaticWriteMethod() throws IntrospectionException {
+		{
+			BeanInfo bi = Introspector.getBeanInfo(WithStaticWriteMethod.class);
+			assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
+			assertThat(hasWriteMethodForProperty(bi, "prop1"), is(false));
+			assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
+			assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
+		}
+		{
+			BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(WithStaticWriteMethod.class));
+			assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
+			assertThat(hasWriteMethodForProperty(bi, "prop1"), is(true));
+			assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
+			assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
+		}
+	}
+
+	static class WithStaticWriteMethod {
+		@SuppressWarnings("unused")
+		public static void setProp1(String prop1) {
+		}
+	}
 }