Merge branch '5.3.x'

This commit is contained in:
Juergen Hoeller 2022-10-18 16:24:35 +02:00
commit cb44e09694
4 changed files with 75 additions and 27 deletions

View File

@ -19,8 +19,10 @@ package org.springframework.beans;
import java.beans.IntrospectionException; import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@ -52,8 +54,10 @@ abstract class PropertyDescriptorUtils {
* @see SimpleBeanInfoFactory * @see SimpleBeanInfoFactory
* @see java.beans.Introspector#getBeanInfo(Class) * @see java.beans.Introspector#getBeanInfo(Class)
*/ */
public static Collection<PropertyDescriptor> determineBasicProperties(Class<?> beanClass) throws IntrospectionException { public static Collection<? extends PropertyDescriptor> determineBasicProperties(Class<?> beanClass)
Map<String, PropertyDescriptor> pdMap = new TreeMap<>(); throws IntrospectionException {
Map<String, BasicPropertyDescriptor> pdMap = new TreeMap<>();
for (Method method : beanClass.getMethods()) { for (Method method : beanClass.getMethods()) {
String methodName = method.getName(); String methodName = method.getName();
@ -81,39 +85,26 @@ abstract class PropertyDescriptorUtils {
continue; continue;
} }
PropertyDescriptor pd = pdMap.get(propertyName); BasicPropertyDescriptor pd = pdMap.get(propertyName);
if (pd != null) { if (pd != null) {
if (setter) { if (setter) {
if (pd.getWriteMethod() == null || if (pd.getWriteMethod() == null ||
pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) { pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
try {
pd.setWriteMethod(method); pd.setWriteMethod(method);
} }
catch (IntrospectionException ex) { else {
// typically a type mismatch -> ignore pd.addWriteMethod(method);
}
} }
} }
else { else {
if (pd.getReadMethod() == null || if (pd.getReadMethod() == null ||
(pd.getReadMethod().getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) { (pd.getReadMethod().getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
try {
pd.setReadMethod(method); pd.setReadMethod(method);
} }
catch (IntrospectionException ex) {
// typically a type mismatch -> ignore
}
}
} }
} }
else { else {
pd = new BasicPropertyDescriptor(propertyName, beanClass); pd = new BasicPropertyDescriptor(propertyName, (!setter ? method : null), (setter ? method : null));
if (setter) {
pd.setWriteMethod(method);
}
else {
pd.setReadMethod(method);
}
pdMap.put(propertyName, pd); pdMap.put(propertyName, pd);
} }
} }
@ -277,8 +268,12 @@ abstract class PropertyDescriptorUtils {
@Nullable @Nullable
private Method writeMethod; private Method writeMethod;
public BasicPropertyDescriptor(String propertyName, Class<?> beanClass) throws IntrospectionException { private final List<Method> alternativeWriteMethods = new ArrayList<>();
super(propertyName, beanClass, null, null);
public BasicPropertyDescriptor(String propertyName, @Nullable Method readMethod, @Nullable Method writeMethod)
throws IntrospectionException {
super(propertyName, readMethod, writeMethod);
} }
@Override @Override
@ -297,11 +292,33 @@ abstract class PropertyDescriptorUtils {
this.writeMethod = writeMethod; this.writeMethod = writeMethod;
} }
public void addWriteMethod(Method writeMethod) {
if (this.writeMethod != null) {
this.alternativeWriteMethods.add(this.writeMethod);
this.writeMethod = null;
}
this.alternativeWriteMethods.add(writeMethod);
}
@Override @Override
@Nullable @Nullable
public Method getWriteMethod() { public Method getWriteMethod() {
if (this.writeMethod == null && !this.alternativeWriteMethods.isEmpty()) {
if (this.readMethod == null) {
return this.alternativeWriteMethods.get(0);
}
else {
for (Method method : this.alternativeWriteMethods) {
if (this.readMethod.getReturnType().isAssignableFrom(method.getParameterTypes()[0])) {
this.writeMethod = method;
break;
}
}
}
}
return this.writeMethod; return this.writeMethod;
} }
} }
} }

View File

@ -48,7 +48,9 @@ class SimpleBeanInfoFactory implements BeanInfoFactory, Ordered {
@Override @Override
@NonNull @NonNull
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException { public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
Collection<PropertyDescriptor> pds = PropertyDescriptorUtils.determineBasicProperties(beanClass); Collection<? extends PropertyDescriptor> pds =
PropertyDescriptorUtils.determineBasicProperties(beanClass);
return new SimpleBeanInfo() { return new SimpleBeanInfo() {
@Override @Override
public PropertyDescriptor[] getPropertyDescriptors() { public PropertyDescriptor[] getPropertyDescriptors() {

View File

@ -153,6 +153,16 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
assertThat(accessor.getPropertyValue("object")).isEqualTo(8); assertThat(accessor.getPropertyValue("object")).isEqualTo(8);
} }
@Test
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");
}
@Test @Test
void propertyDescriptors() throws Exception { void propertyDescriptors() throws Exception {
TestBean target = new TestBean(); TestBean target = new TestBean();
@ -348,6 +358,24 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
} }
public static class SetterOverload {
public String value;
public void setObject(Integer length) {
this.value = length.toString();
}
public void setObject(String object) {
this.value = object;
}
public String getObject() {
return this.value;
}
}
public static class GetterWithOptional { public static class GetterWithOptional {
public TestBean value; public TestBean value;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 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.
@ -95,6 +95,8 @@ public class Jsr310DateTimeFormatAnnotationFormatterFactory extends EmbeddedValu
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) { public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
List<String> resolvedFallbackPatterns = new ArrayList<>(); List<String> resolvedFallbackPatterns = new ArrayList<>();
for (String fallbackPattern : annotation.fallbackPatterns()) { for (String fallbackPattern : annotation.fallbackPatterns()) {
String resolvedFallbackPattern = resolveEmbeddedValue(fallbackPattern); String resolvedFallbackPattern = resolveEmbeddedValue(fallbackPattern);
@ -103,7 +105,6 @@ public class Jsr310DateTimeFormatAnnotationFormatterFactory extends EmbeddedValu
} }
} }
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
return new TemporalAccessorParser((Class<? extends TemporalAccessor>) fieldType, return new TemporalAccessorParser((Class<? extends TemporalAccessor>) fieldType,
formatter, resolvedFallbackPatterns.toArray(new String[0]), annotation); formatter, resolvedFallbackPatterns.toArray(new String[0]), annotation);
} }