Browse Source

Introduce write method fallback step for overloaded setter methods

Closes gh-31872
pull/31886/head
Juergen Hoeller 2 years ago
parent
commit
bd65a19d71
  1. 8
      spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java
  2. 18
      spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
  3. 24
      spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java
  4. 27
      spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java

8
spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java

@ -461,7 +461,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA @@ -461,7 +461,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
if (!ph.setValueFallbackIfPossible(pv.getValue())) {
throw ex;
}
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
@ -1061,6 +1063,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA @@ -1061,6 +1063,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
public abstract Object getValue() throws Exception;
public abstract void setValue(@Nullable Object value) throws Exception;
public boolean setValueFallbackIfPossible(@Nullable Object value) {
return false;
}
}

18
spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java

@ -19,6 +19,8 @@ package org.springframework.beans; @@ -19,6 +19,8 @@ package org.springframework.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
@ -278,6 +280,22 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements @@ -278,6 +280,22 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
}
@Override
public boolean setValueFallbackIfPossible(@Nullable Object value) {
Method writeMethod = this.pd.getWriteMethodFallback(value != null ? value.getClass() : null);
if (writeMethod != null) {
ReflectionUtils.makeAccessible(writeMethod);
try {
writeMethod.invoke(getWrappedInstance(), value);
return true;
}
catch (Exception ex) {
LogFactory.getLog(BeanPropertyHandler.class).debug("Write method fallback failed", ex);
}
}
return false;
}
}
}

24
spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java

@ -54,7 +54,9 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { @@ -54,7 +54,9 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
private final Method writeMethod;
@Nullable
private volatile Set<Method> ambiguousWriteMethods;
private Set<Method> ambiguousWriteMethods;
private volatile boolean ambiguousWriteMethodsLogged;
@Nullable
private MethodParameter writeMethodParameter;
@ -147,16 +149,28 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { @@ -147,16 +149,28 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
public Method getWriteMethodForActualAccess() {
Assert.state(this.writeMethod != null, "No write method available");
Set<Method> ambiguousCandidates = this.ambiguousWriteMethods;
if (ambiguousCandidates != null) {
this.ambiguousWriteMethods = null;
if (this.ambiguousWriteMethods != null && !this.ambiguousWriteMethodsLogged) {
this.ambiguousWriteMethodsLogged = true;
LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).debug("Non-unique JavaBean property '" +
getName() + "' being accessed! Ambiguous write methods found next to actually used [" +
this.writeMethod + "]: " + ambiguousCandidates);
this.writeMethod + "]: " + this.ambiguousWriteMethods);
}
return this.writeMethod;
}
@Nullable
public Method getWriteMethodFallback(@Nullable Class<?> valueType) {
if (this.ambiguousWriteMethods != null) {
for (Method method : this.ambiguousWriteMethods) {
Class<?> paramType = method.getParameterTypes()[0];
if (valueType != null ? paramType.isAssignableFrom(valueType) : !paramType.isPrimitive()) {
return method;
}
}
}
return null;
}
public MethodParameter getWriteMethodParameter() {
Assert.state(this.writeMethodParameter != null, "No write method available");
return this.writeMethodParameter;

27
spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.beans;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
@ -172,10 +173,26 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests { @@ -172,10 +173,26 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
void setterOverload() {
SetterOverload target = new SetterOverload();
BeanWrapper accessor = createAccessor(target);
accessor.setPropertyValue("object", "a String");
assertThat(target.value).isEqualTo("a String");
assertThat(target.getObject()).isEqualTo("a String");
assertThat(accessor.getPropertyValue("object")).isEqualTo("a String");
accessor.setPropertyValue("object", 1000);
assertThat(target.value).isEqualTo("1000");
assertThat(target.getObject()).isEqualTo("1000");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000");
accessor.setPropertyValue("value", 1000);
assertThat(target.value).isEqualTo("1000i");
assertThat(target.getObject()).isEqualTo("1000i");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000i");
accessor.setPropertyValue("value", Duration.ofSeconds(1000));
assertThat(target.value).isEqualTo("1000s");
assertThat(target.getObject()).isEqualTo("1000s");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000s");
}
@Test
@ -382,7 +399,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests { @@ -382,7 +399,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String value;
public void setObject(Integer length) {
this.value = length.toString();
this.value = length + "i";
}
public void setObject(String object) {
@ -392,6 +409,14 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests { @@ -392,6 +409,14 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String getObject() {
return this.value;
}
public void setValue(int length) {
this.value = length + "i";
}
public void setValue(Duration duration) {
this.value = duration.getSeconds() + "s";
}
}

Loading…
Cancel
Save