You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2008/01/31 00:42:47 UTC

svn commit: r616961 - in /openjpa/branches/1.0.x: openjpa-kernel-5/src/test/ openjpa-kernel-5/src/test/java/ openjpa-kernel-5/src/test/java/org/ openjpa-kernel-5/src/test/java/org/apache/ openjpa-kernel-5/src/test/java/org/apache/openjpa/ openjpa-kerne...

Author: pcl
Date: Wed Jan 30 15:42:32 2008
New Revision: 616961

URL: http://svn.apache.org/viewvc?rev=616961&view=rev
Log:
OPENJPA-251, OPENJPA-329. I was not able to reproduce OPENJPA-251, but this logic should avoid the issue. I did not build a direct reproducer for OPENJPA-329, but I believe that the unit test covers the use case identified by that issue.

Added:
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/
    openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/TestGetDeclaredMethod.java
Modified:
    openjpa/branches/1.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
    openjpa/branches/1.0.x/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties

Added: openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/TestGetDeclaredMethod.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/TestGetDeclaredMethod.java?rev=616961&view=auto
==============================================================================
--- openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/TestGetDeclaredMethod.java (added)
+++ openjpa/branches/1.0.x/openjpa-kernel-5/src/test/java/org/apache/openjpa/enhance/TestGetDeclaredMethod.java Wed Jan 30 15:42:32 2008
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.openjpa.enhance;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that {@link Reflection#getDeclaredMethod(Class, String, Class)}
+ * returns the most-derived class's method when called from a type hierarchy.
+ * See OPENJPA-251.
+ */
+public class TestGetDeclaredMethod extends TestCase {
+
+    public void testGetDeclaredMethod() {
+        Method meth =
+            Reflection.getDeclaredMethod(Impl.class, "getObject", null);
+        assertEquals(Impl.class, meth.getDeclaringClass());
+        assertEquals(String.class, meth.getReturnType());
+    }
+
+    public void testMostDerived() throws NoSuchMethodException {
+        Method impl = Impl.class.getDeclaredMethod("getObject", null);
+        Method iface = Iface.class.getDeclaredMethod("getObject", null);
+        Method other = Other.class.getDeclaredMethod("getObject", null);
+        assertEquals(Impl.class, Reflection.mostDerived(impl, iface)
+            .getDeclaringClass());
+        assertEquals(Impl.class, Reflection.mostDerived(iface, impl)
+            .getDeclaringClass());
+        try {
+            Reflection.mostDerived(iface, other);
+            fail("'iface' and 'other' are not from related types");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testGenerics() throws NoSuchMethodException {
+        List<Method> meths = new ArrayList<Method>();
+        for (Method meth : GenericsImpl.class.getDeclaredMethods()) {
+            if ("getObject".equals(meth.getName()))
+                meths.add(meth);
+        }
+        assertEquals(2, meths.size());
+        assertEquals(String.class, Reflection.mostDerived(meths.get(0),
+            meths.get(1)).getReturnType());
+    }
+    
+    interface Iface {
+        Object getObject();
+    }
+
+    static class Impl implements Iface {
+        public String getObject() {
+            return "string";
+        }
+    }
+
+    static class Other {
+        public String getObject() {
+            return "other";
+        }
+    }
+
+    interface GenericsIface<T> {
+        public T getObject();
+    }
+
+    static class GenericsImpl implements GenericsIface {
+        public String getObject() {
+            return null;
+        }
+    }
+}

Modified: openjpa/branches/1.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java?rev=616961&r1=616960&r2=616961&view=diff
==============================================================================
--- openjpa/branches/1.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java (original)
+++ openjpa/branches/1.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java Wed Jan 30 15:42:32 2008
@@ -112,27 +112,62 @@
      * Invokes <code>cls.getDeclaredMethods()</code>, and returns the method
      * that matches the <code>name</code> and <code>param</code> arguments.
      * Avoids the exception thrown by <code>Class.getDeclaredMethod()</code>
-     * for performance reasons. <code>param</code> may be null.
+     * for performance reasons. <code>param</code> may be null. Additionally,
+     * if there are multiple methods with different return types, this will
+     * return the method defined in the least-derived class.
      *
      * @since 0.9.8
      */
-    private static Method getDeclaredMethod(Class cls, String name,
+    static Method getDeclaredMethod(Class cls, String name,
         Class param) {
         Method[] methods = (Method[]) AccessController.doPrivileged(
             J2DoPrivHelper.getDeclaredMethodsAction(cls));
+        Method candidate = null;
         for (int i = 0 ; i < methods.length; i++) {
     	    if (name.equals(methods[i].getName())) {
                 Class[] methodParams = methods[i].getParameterTypes();
                 if (param == null && methodParams.length == 0)
-                    return methods[i];
-                if (param != null && methodParams.length == 1
+                    candidate = mostDerived(methods[i], candidate);
+                else if (param != null && methodParams.length == 1
                     && param.equals(methodParams[0]))
-                    return methods[i];
+                    candidate = mostDerived(methods[i], candidate);
             }
         }
-        return null;
+        return candidate;
     }
-    
+
+    static Method mostDerived(Method meth1, Method meth2) {
+        if (meth1 == null)
+            return meth2;
+        if (meth2 == null)
+            return meth1;
+        
+        Class cls2 = meth2.getDeclaringClass();
+        Class cls1 = meth1.getDeclaringClass();
+
+        if (cls1.equals(cls2)) {
+            Class ret1 = meth1.getReturnType();
+            Class ret2 = meth2.getReturnType();
+            if (ret1.isAssignableFrom(ret2))
+                return meth2;
+            else if (ret2.isAssignableFrom(ret1))
+                return meth1;
+            else
+                throw new IllegalArgumentException(
+                    _loc.get("most-derived-unrelated-same-type", meth1, meth2)
+                        .getMessage());
+        } else {
+            if (cls1.isAssignableFrom(cls2))
+                return meth2;
+            else if (cls2.isAssignableFrom(cls1))
+                return meth1;
+            else
+                throw new IllegalArgumentException(
+                    _loc.get("most-derived-unrelated", meth1, meth2)
+                        .getMessage());
+        }
+    }
+
     /**
      * Return the field with the given name, optionally throwing an exception
      * if none.

Modified: openjpa/branches/1.0.x/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/branches/1.0.x/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties?rev=616961&r1=616960&r2=616961&view=diff
==============================================================================
--- openjpa/branches/1.0.x/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties (original)
+++ openjpa/branches/1.0.x/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties Wed Jan 30 15:42:32 2008
@@ -199,3 +199,8 @@
     to other unenhanced types that were not specified. These unspecified types \
     are: {1}
 enhance-error: An error occurred while enhancing {0}. Exception message: {1}
+most-derived-unrelated: Methods "{0}" and "{1}" are defined in types that do \
+    not have an interface or superclass inheritance relationship.
+most-derived-unrelated-same-type: Methods "{0}" and "{1}" are defined in the same \
+    type, but the method return types do not have an interface or superclass \
+    inheritance relationship.