Skip to content

Commit 93b0b66

Browse files
committed
Merge branch '6.0.x'
# Conflicts: # spring-beans/src/main/java/org/springframework/beans/BeanUtils.java # spring-core/src/main/java/org/springframework/core/ResolvableType.java # spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
2 parents d232636 + 925fa02 commit 93b0b66

File tree

7 files changed

+53
-35
lines changed

7 files changed

+53
-35
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,18 +1013,20 @@ public String toString() {
10131013
*/
10141014
protected abstract static class PropertyHandler {
10151015

1016+
@Nullable
10161017
private final Class<?> propertyType;
10171018

10181019
private final boolean readable;
10191020

10201021
private final boolean writable;
10211022

1022-
public PropertyHandler(Class<?> propertyType, boolean readable, boolean writable) {
1023+
public PropertyHandler(@Nullable Class<?> propertyType, boolean readable, boolean writable) {
10231024
this.propertyType = propertyType;
10241025
this.readable = readable;
10251026
this.writable = writable;
10261027
}
10271028

1029+
@Nullable
10281030
public Class<?> getPropertyType() {
10291031
return this.propertyType;
10301032
}

spring-beans/src/main/java/org/springframework/beans/BeanUtils.java

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.lang.reflect.InvocationTargetException;
2424
import java.lang.reflect.Method;
2525
import java.lang.reflect.Modifier;
26+
import java.lang.reflect.Type;
2627
import java.util.Arrays;
2728
import java.util.Collections;
2829
import java.util.HashSet;
@@ -613,8 +614,8 @@ public static Class<?> findPropertyType(String propertyName, @Nullable Class<?>.
613614
* @return a corresponding MethodParameter object
614615
*/
615616
public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {
616-
if (pd instanceof GenericTypeAwarePropertyDescriptor typeAwarePd) {
617-
return new MethodParameter(typeAwarePd.getWriteMethodParameter());
617+
if (pd instanceof GenericTypeAwarePropertyDescriptor gpd) {
618+
return new MethodParameter(gpd.getWriteMethodParameter());
618619
}
619620
else {
620621
Method writeMethod = pd.getWriteMethod();
@@ -781,38 +782,28 @@ private static void copyProperties(Object source, Object target, @Nullable Class
781782
if (editable != null) {
782783
if (!editable.isInstance(target)) {
783784
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
784-
"] not assignable to Editable class [" + editable.getName() + "]");
785+
"] not assignable to editable class [" + editable.getName() + "]");
785786
}
786787
actualEditable = editable;
787788
}
788789
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
789790
Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
791+
CachedIntrospectionResults sourceResults = (actualEditable != source.getClass() ?
792+
CachedIntrospectionResults.forClass(source.getClass()) : null);
790793

791794
for (PropertyDescriptor targetPd : targetPds) {
792795
Method writeMethod = targetPd.getWriteMethod();
793796
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
794-
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
797+
PropertyDescriptor sourcePd = (sourceResults != null ?
798+
sourceResults.getPropertyDescriptor(targetPd.getName()) : targetPd);
795799
if (sourcePd != null) {
796800
Method readMethod = sourcePd.getReadMethod();
797801
if (readMethod != null) {
798-
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
799-
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
800-
801-
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
802-
boolean isAssignable =
803-
(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
804-
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
805-
targetResolvableType.isAssignableFrom(sourceResolvableType));
806-
807-
if (isAssignable) {
802+
if (isAssignable(writeMethod, readMethod)) {
808803
try {
809-
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
810-
readMethod.setAccessible(true);
811-
}
804+
ReflectionUtils.makeAccessible(readMethod);
812805
Object value = readMethod.invoke(source);
813-
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
814-
writeMethod.setAccessible(true);
815-
}
806+
ReflectionUtils.makeAccessible(writeMethod);
816807
writeMethod.invoke(target, value);
817808
}
818809
catch (Throwable ex) {
@@ -826,6 +817,24 @@ private static void copyProperties(Object source, Object target, @Nullable Class
826817
}
827818
}
828819

820+
private static boolean isAssignable(Method writeMethod, Method readMethod) {
821+
Type paramType = writeMethod.getGenericParameterTypes()[0];
822+
if (paramType instanceof Class<?> clazz) {
823+
return ClassUtils.isAssignable(clazz, readMethod.getReturnType());
824+
}
825+
else if (paramType.equals(readMethod.getGenericReturnType())) {
826+
return true;
827+
}
828+
else {
829+
ResolvableType sourceType = ResolvableType.forMethodReturnType(readMethod);
830+
ResolvableType targetType = ResolvableType.forMethodParameter(writeMethod, 0);
831+
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
832+
return (sourceType.hasUnresolvableGenerics() || targetType.hasUnresolvableGenerics() ?
833+
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
834+
targetType.isAssignableFrom(sourceType));
835+
}
836+
}
837+
829838

830839
/**
831840
* Inner class to avoid a hard dependency on Kotlin at runtime.
@@ -899,7 +908,6 @@ public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
899908
}
900909
return kotlinConstructor.callBy(argParameters);
901910
}
902-
903911
}
904912

905913
}

spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ public Object getValue() throws Exception {
144144
ReflectionUtils.makeAccessible(this.field);
145145
return this.field.get(getWrappedInstance());
146146
}
147-
148147
catch (IllegalAccessException ex) {
149148
throw new InvalidPropertyException(getWrappedClass(),
150149
this.field.getName(), "Field is not accessible", ex);

spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,10 @@ protected ResolvableType getGenericApplicationEventType(String fieldName) {
3636
}
3737
}
3838

39+
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
40+
return new GenericTestEvent<>(this, payload);
41+
}
42+
3943

4044
protected static class GenericTestEvent<T> extends ApplicationEvent {
4145

@@ -51,6 +55,7 @@ public T getPayload() {
5155
}
5256
}
5357

58+
5459
protected static class SmartGenericTestEvent<T> extends GenericTestEvent<T> implements ResolvableTypeProvider {
5560

5661
private final ResolvableType resolvableType;
@@ -67,52 +72,55 @@ public ResolvableType getResolvableType() {
6772
}
6873
}
6974

75+
7076
protected static class StringEvent extends GenericTestEvent<String> {
7177

7278
public StringEvent(Object source, String payload) {
7379
super(source, payload);
7480
}
7581
}
7682

83+
7784
protected static class LongEvent extends GenericTestEvent<Long> {
7885

7986
public LongEvent(Object source, Long payload) {
8087
super(source, payload);
8188
}
8289
}
8390

84-
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
85-
return new GenericTestEvent<>(this, payload);
86-
}
87-
8891

8992
static class GenericEventListener implements ApplicationListener<GenericTestEvent<?>> {
93+
9094
@Override
9195
public void onApplicationEvent(GenericTestEvent<?> event) {
9296
}
9397
}
9498

99+
95100
static class ObjectEventListener implements ApplicationListener<GenericTestEvent<Object>> {
101+
96102
@Override
97103
public void onApplicationEvent(GenericTestEvent<Object> event) {
98104
}
99105
}
100106

101-
static class UpperBoundEventListener
102-
implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
107+
108+
static class UpperBoundEventListener implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
103109

104110
@Override
105111
public void onApplicationEvent(GenericTestEvent<? extends RuntimeException> event) {
106112
}
107113
}
108114

115+
109116
static class StringEventListener implements ApplicationListener<GenericTestEvent<String>> {
110117

111118
@Override
112119
public void onApplicationEvent(GenericTestEvent<String> event) {
113120
}
114121
}
115122

123+
116124
@SuppressWarnings("rawtypes")
117125
static class RawApplicationListener implements ApplicationListener {
118126

@@ -121,10 +129,10 @@ public void onApplicationEvent(ApplicationEvent event) {
121129
}
122130
}
123131

132+
124133
static class TestEvents {
125134

126135
public GenericTestEvent<?> wildcardEvent;
127-
128136
}
129137

130138
}

spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ public void genericListenerStrictTypeNotMatchTypeErasure() {
104104

105105
@Test
106106
public void genericListenerStrictTypeSubClass() {
107-
supportsEventType(false, ObjectEventListener.class, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
107+
supportsEventType(false, ObjectEventListener.class,
108+
ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
108109
}
109110

110111
@Test

spring-core/src/main/java/org/springframework/core/ResolvableType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,12 @@ public ResolvableType getGeneric(@Nullable int... indexes) {
714714
}
715715

716716
/**
717-
* Return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters of
717+
* Return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters of
718718
* this type. If no generics are available an empty array is returned. If you need to
719719
* access a specific generic consider using the {@link #getGeneric(int...)} method as
720720
* it allows access to nested generics and protects against
721721
* {@code IndexOutOfBoundsExceptions}.
722-
* @return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters
722+
* @return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters
723723
* (never {@code null})
724724
* @see #hasGenerics()
725725
* @see #getGeneric(int...)

spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ void getComponentTypeForClassArray() throws Exception {
360360
ResolvableType type = ResolvableType.forField(field);
361361
assertThat(type.isArray()).isTrue();
362362
assertThat(type.getComponentType().getType())
363-
.isEqualTo(((Class) field.getGenericType()).componentType());
363+
.isEqualTo(((Class) field.getGenericType()).componentType());
364364
}
365365

366366
@Test

0 commit comments

Comments
 (0)