diff --git a/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java b/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java
index ea47b61b45e..4adf3acac6d 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -41,13 +42,9 @@ import org.springframework.util.ReflectionUtils;
*
See
* The Java Language Specification for more details on the use of bridge methods.
*
- *
Only usable on JDK 1.5 and higher. Use an appropriate {@link JdkVersion}
- * check before calling this class if a fallback for JDK 1.4 is desirable.
- *
* @author Rob Harrop
* @author Juergen Hoeller
* @since 2.0
- * @see JdkVersion
*/
public abstract class BridgeMethodResolver {
@@ -62,7 +59,6 @@ public abstract class BridgeMethodResolver {
if (bridgeMethod == null || !bridgeMethod.isBridge()) {
return bridgeMethod;
}
-
// Gather all methods with matching name and parameter size.
List candidateMethods = new ArrayList();
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
@@ -71,16 +67,12 @@ public abstract class BridgeMethodResolver {
candidateMethods.add(candidateMethod);
}
}
-
- Method result;
- // Now perform simple quick checks.
+ // Now perform simple quick check.
if (candidateMethods.size() == 1) {
- result = candidateMethods.get(0);
- }
- else {
- result = searchCandidates(candidateMethods, bridgeMethod);
+ return candidateMethods.get(0);
}
-
+ // Search for candidate match.
+ Method result = searchCandidates(candidateMethods, bridgeMethod);
if (result == null) {
throw new IllegalStateException(
"Unable to locate bridged method for bridge method '" + bridgeMethod + "'");
@@ -95,13 +87,23 @@ public abstract class BridgeMethodResolver {
* @return the bridged method, or null if none found
*/
private static Method searchCandidates(List candidateMethods, Method bridgeMethod) {
+ if (candidateMethods.isEmpty()) {
+ return null;
+ }
Map typeParameterMap = GenericTypeResolver.getTypeVariableMap(bridgeMethod.getDeclaringClass());
+ Method previousMethod = null;
+ boolean sameSig = true;
for (Method candidateMethod : candidateMethods) {
if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) {
return candidateMethod;
}
+ else if (previousMethod != null) {
+ sameSig = sameSig &&
+ Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes());
+ }
+ previousMethod = candidateMethod;
}
- return null;
+ return (sameSig ? candidateMethods.get(0) : null);
}
/**
@@ -185,7 +187,8 @@ public abstract class BridgeMethodResolver {
}
}
// A non-array type: compare the type itself.
- if (!candidateParameter.equals(GenericTypeResolver.resolveType(genericParameter, typeVariableMap))) {
+ Class resolvedParameter = GenericTypeResolver.resolveType(genericParameter, typeVariableMap);
+ if (!candidateParameter.equals(resolvedParameter)) {
return false;
}
}
diff --git a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java
new file mode 100644
index 00000000000..ba55810ffed
--- /dev/null
+++ b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.orm.hibernate3;
+
+import java.io.Serializable;
+
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer;
+import org.junit.Test;
+
+import org.springframework.beans.BeanUtils;
+
+/**
+ * Test for compatibility of Spring's BeanUtils and its BridgeMethodResolver use
+ * when operating on a Hibernate-generated CGLIB proxy class.
+ *
+ * @author Arnout Engelen
+ * @author Juergen Hoeller
+ */
+public class CglibProxyBridgeMethodTests {
+
+ @Test
+ public void introspectHibernateProxyForGenericClass() {
+ BeanUtils.getPropertyDescriptor(CglibInstantieMedewerker.class, "organisatie");
+ Class> clazz = CGLIBLazyInitializer.getProxyFactory(
+ CglibInstantieMedewerker.class, new Class[] {HibernateProxy.class});
+ BeanUtils.getPropertyDescriptor(clazz, "organisatie");
+ }
+
+
+ public interface CglibIOrganisatie {
+ }
+
+
+ public class CglibOrganisatie implements CglibIOrganisatie {
+ }
+
+
+ public class CglibInstantie extends CglibOrganisatie {
+ }
+
+
+ public interface CglibIOrganisatieMedewerker {
+
+ void setOrganisatie(T organisatie);
+ }
+
+
+ public class CglibOrganisatieMedewerker implements CglibIOrganisatieMedewerker {
+
+ public void setOrganisatie(CglibOrganisatie organisatie) {
+ }
+ }
+
+
+ public class CglibInstantieMedewerker extends CglibOrganisatieMedewerker implements Serializable {
+ }
+
+}