Skip to content

Commit dae4366

Browse files
committed
Merge branch '6.1.x'
2 parents 903493e + 345daaa commit dae4366

File tree

2 files changed

+87
-16
lines changed

2 files changed

+87
-16
lines changed

spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java

+81-14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import org.springframework.beans.testfixture.beans.DerivedTestBean;
4343
import org.springframework.beans.testfixture.beans.ITestBean;
4444
import org.springframework.beans.testfixture.beans.TestBean;
45+
import org.springframework.cglib.proxy.Enhancer;
46+
import org.springframework.cglib.proxy.MethodInterceptor;
4547
import org.springframework.core.io.Resource;
4648
import org.springframework.core.io.ResourceEditor;
4749
import org.springframework.lang.Nullable;
@@ -322,12 +324,13 @@ void copyPropertiesIgnoresGenericsIfSourceOrTargetHasUnresolvableGenerics() thro
322324
Order original = new Order("test", List.of("foo", "bar"));
323325

324326
// Create a Proxy that loses the generic type information for the getLineItems() method.
325-
OrderSummary proxy = proxyOrder(original);
327+
OrderSummary proxy = (OrderSummary) Proxy.newProxyInstance(getClass().getClassLoader(),
328+
new Class<?>[] {OrderSummary.class}, new OrderInvocationHandler(original));
326329
assertThat(OrderSummary.class.getDeclaredMethod("getLineItems").toGenericString())
327-
.contains("java.util.List<java.lang.String>");
330+
.contains("java.util.List<java.lang.String>");
328331
assertThat(proxy.getClass().getDeclaredMethod("getLineItems").toGenericString())
329-
.contains("java.util.List")
330-
.doesNotContain("<java.lang.String>");
332+
.contains("java.util.List")
333+
.doesNotContain("<java.lang.String>");
331334

332335
// Ensure that our custom Proxy works as expected.
333336
assertThat(proxy.getId()).isEqualTo("test");
@@ -340,6 +343,23 @@ void copyPropertiesIgnoresGenericsIfSourceOrTargetHasUnresolvableGenerics() thro
340343
assertThat(target.getLineItems()).containsExactly("foo", "bar");
341344
}
342345

346+
@Test // gh-32888
347+
public void copyPropertiesWithGenericCglibCLass() {
348+
Enhancer enhancer = new Enhancer();
349+
enhancer.setSuperclass(User.class);
350+
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> proxy.invokeSuper(obj, args));
351+
User user = (User) enhancer.create();
352+
user.setId(1);
353+
user.setName("proxy");
354+
user.setAddress("addr");
355+
356+
User target = new User();
357+
BeanUtils.copyProperties(user, target);
358+
assertThat(target.getId()).isEqualTo(user.getId());
359+
assertThat(target.getName()).isEqualTo(user.getName());
360+
assertThat(target.getAddress()).isEqualTo(user.getAddress());
361+
}
362+
343363
@Test
344364
void copyPropertiesWithEditable() throws Exception {
345365
TestBean tb = new TestBean();
@@ -520,6 +540,7 @@ public void setNumber(Number number) {
520540
}
521541
}
522542

543+
523544
@SuppressWarnings("unused")
524545
private static class IntegerHolder {
525546

@@ -534,6 +555,7 @@ public void setNumber(Integer number) {
534555
}
535556
}
536557

558+
537559
@SuppressWarnings("unused")
538560
private static class WildcardListHolder1 {
539561

@@ -548,6 +570,7 @@ public void setList(List<?> list) {
548570
}
549571
}
550572

573+
551574
@SuppressWarnings("unused")
552575
private static class WildcardListHolder2 {
553576

@@ -562,6 +585,7 @@ public void setList(List<?> list) {
562585
}
563586
}
564587

588+
565589
@SuppressWarnings("unused")
566590
private static class NumberUpperBoundedWildcardListHolder {
567591

@@ -576,6 +600,7 @@ public void setList(List<? extends Number> list) {
576600
}
577601
}
578602

603+
579604
@SuppressWarnings("unused")
580605
private static class NumberListHolder {
581606

@@ -590,6 +615,7 @@ public void setList(List<Number> list) {
590615
}
591616
}
592617

618+
593619
@SuppressWarnings("unused")
594620
private static class IntegerListHolder1 {
595621

@@ -604,6 +630,7 @@ public void setList(List<Integer> list) {
604630
}
605631
}
606632

633+
607634
@SuppressWarnings("unused")
608635
private static class IntegerListHolder2 {
609636

@@ -618,6 +645,7 @@ public void setList(List<Integer> list) {
618645
}
619646
}
620647

648+
621649
@SuppressWarnings("unused")
622650
private static class LongListHolder {
623651

@@ -798,6 +826,7 @@ public void setValue(String aValue) {
798826
}
799827
}
800828

829+
801830
private static class BeanWithNullableTypes {
802831

803832
private Integer counter;
@@ -828,6 +857,7 @@ public String getValue() {
828857
}
829858
}
830859

860+
831861
private static class BeanWithPrimitiveTypes {
832862

833863
private boolean flag;
@@ -840,7 +870,6 @@ private static class BeanWithPrimitiveTypes {
840870
private char character;
841871
private String text;
842872

843-
844873
@SuppressWarnings("unused")
845874
public BeanWithPrimitiveTypes(boolean flag, byte byteCount, short shortCount, int intCount, long longCount,
846875
float floatCount, double doubleCount, char character, String text) {
@@ -891,22 +920,22 @@ public char getCharacter() {
891920
public String getText() {
892921
return text;
893922
}
894-
895923
}
896924

925+
897926
private static class PrivateBeanWithPrivateConstructor {
898927

899928
private PrivateBeanWithPrivateConstructor() {
900929
}
901930
}
902931

932+
903933
@SuppressWarnings("unused")
904934
private static class Order {
905935

906936
private String id;
907937
private List<String> lineItems;
908938

909-
910939
Order() {
911940
}
912941

@@ -937,6 +966,7 @@ public String toString() {
937966
}
938967
}
939968

969+
940970
private interface OrderSummary {
941971

942972
String getId();
@@ -945,17 +975,10 @@ private interface OrderSummary {
945975
}
946976

947977

948-
private OrderSummary proxyOrder(Order order) {
949-
return (OrderSummary) Proxy.newProxyInstance(getClass().getClassLoader(),
950-
new Class<?>[] { OrderSummary.class }, new OrderInvocationHandler(order));
951-
}
952-
953-
954978
private static class OrderInvocationHandler implements InvocationHandler {
955979

956980
private final Order order;
957981

958-
959982
OrderInvocationHandler(Order order) {
960983
this.order = order;
961984
}
@@ -973,4 +996,48 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
973996
}
974997
}
975998

999+
1000+
private static class GenericBaseModel<T> {
1001+
1002+
public GenericBaseModel() {
1003+
}
1004+
1005+
private T id;
1006+
private String name;
1007+
1008+
public T getId() {
1009+
return id;
1010+
}
1011+
1012+
public void setId(T id) {
1013+
this.id = id;
1014+
}
1015+
1016+
public String getName() {
1017+
return name;
1018+
}
1019+
1020+
public void setName(String name) {
1021+
this.name = name;
1022+
}
1023+
}
1024+
1025+
1026+
private static class User extends GenericBaseModel<Integer> {
1027+
1028+
private String address;
1029+
1030+
public User() {
1031+
super();
1032+
}
1033+
1034+
public String getAddress() {
1035+
return address;
1036+
}
1037+
1038+
public void setAddress(String address) {
1039+
this.address = address;
1040+
}
1041+
}
1042+
9761043
}

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,12 @@ public static Method getMostSpecificMethod(Method bridgeMethod, @Nullable Class<
101101

102102
private static Method resolveBridgeMethod(Method bridgeMethod, Class<?> targetClass) {
103103
boolean localBridge = (targetClass == bridgeMethod.getDeclaringClass());
104+
Class<?> userClass = targetClass;
104105
if (!bridgeMethod.isBridge() && localBridge) {
105-
return bridgeMethod;
106+
userClass = ClassUtils.getUserClass(targetClass);
107+
if (userClass == targetClass) {
108+
return bridgeMethod;
109+
}
106110
}
107111

108112
Object cacheKey = (localBridge ? bridgeMethod : new MethodClassKey(bridgeMethod, targetClass));
@@ -111,7 +115,7 @@ private static Method resolveBridgeMethod(Method bridgeMethod, Class<?> targetCl
111115
// Gather all methods with matching name and parameter size.
112116
List<Method> candidateMethods = new ArrayList<>();
113117
MethodFilter filter = (candidateMethod -> isBridgedCandidateFor(candidateMethod, bridgeMethod));
114-
ReflectionUtils.doWithMethods(targetClass, candidateMethods::add, filter);
118+
ReflectionUtils.doWithMethods(userClass, candidateMethods::add, filter);
115119
if (!candidateMethods.isEmpty()) {
116120
bridgedMethod = (candidateMethods.size() == 1 ? candidateMethods.get(0) :
117121
searchCandidates(candidateMethods, bridgeMethod));

0 commit comments

Comments
 (0)