This is the mail archive of the mauve-patches@sourceware.org mailing list for the Mauve project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

FYI: New test on special method handling on proxy


Hi,
  I added a test to ensure that in the case of redefinition of toString,
hashCode or equals (ie all public non final methods of Object) in an
interface, the method created in the Proxy still have Object.class as
declaring class and not the interface itself.

2006-02-19  Olivier Jolly  <olivier.jolly@pcedev.com>

    * gnu/testlet/java/lang/reflect/Proxy/DeclaringClass.java: New file.
    * gnu/testlet/java/lang/reflect/Proxy/ProxyUtils.java: New file.

  The fix is arriving shortly in classpath.
Cheers

Olivier
Index: gnu/testlet/java/lang/reflect/Proxy/DeclaringClass.java
===================================================================
RCS file: gnu/testlet/java/lang/reflect/Proxy/DeclaringClass.java
diff -N gnu/testlet/java/lang/reflect/Proxy/DeclaringClass.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/testlet/java/lang/reflect/Proxy/DeclaringClass.java	19 Feb 2006 21:20:56 -0000
@@ -0,0 +1,168 @@
+/* DeclaringClass.java -- Checks for the declaring class of the special 
+ methods in Object, namely toString, Equals and hashCode
+ Copyright (C) 2006 Olivier Jolly <olivier.jolly@pcedev.com>
+ This file is part of Mauve.
+
+ Mauve is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Mauve is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Mauve; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ */
+
+// Tags: JDK1.3
+// Uses: ProxyUtils
+
+
+package gnu.testlet.java.lang.reflect.Proxy;
+
+import gnu.testlet.TestHarness;
+import gnu.testlet.Testlet;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Checks that the public non final methods of Objects (ie equals, toString and
+ * hashCode) are built in Proxy with Object as declaring class whatever the
+ * method definition of the interfaces used for the proxy creation
+ * @author Olivier Jolly <olivier.jolly@pcedev.com>
+ */
+public class DeclaringClass implements Testlet
+{
+
+  public void test(TestHarness harness)
+  {
+    Class[] testableInterfaces = { Serializable.class,
+                                  WithObjectOverrides.class,
+                                  WithoutObjectOverrides.class, Base.class,
+                                  Derived.class };
+    for (int i = 0; i < testableInterfaces.length; i++)
+      {
+        Class interfaceItem = testableInterfaces[i];
+        Object proxy = Proxy.newProxyInstance(
+                                              this.getClass().getClassLoader(),
+                                              new Class[] { interfaceItem },
+                                              new ExpectObjectDeclaringClassIfPossibleHandler(
+                                                                                              harness));
+        harness.checkPoint("Testing " + interfaceItem);
+        proxy.equals(new Object());
+        proxy.hashCode();
+        proxy.toString();
+      }
+  }
+
+  /**
+   * Handler which checks that invoked public non final methods of Object have
+   * their declared class set to Object.class
+   */
+  private static class ExpectObjectDeclaringClassIfPossibleHandler implements
+      InvocationHandler
+  {
+
+    static Collection objectMethods;
+
+    static
+      {
+        objectMethods = new ArrayList();
+        try
+          {
+            objectMethods.add(Object.class.getMethod(
+                                                     "equals",
+                                                     new Class[] { Object.class }));
+            objectMethods.add(Object.class.getMethod("hashCode", null));
+            objectMethods.add(Object.class.getMethod("toString", null));
+          }
+        catch (NoSuchMethodException e)
+          {
+            e.printStackTrace();
+            throw new Error("Missing core methods in Object");
+          }
+      }
+
+    TestHarness harness;
+
+    public ExpectObjectDeclaringClassIfPossibleHandler(TestHarness harness)
+    {
+      this.harness = harness;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable
+    {
+      boolean expectObjectDeclaringClass = false;
+      for (Iterator iter = objectMethods.iterator(); iter.hasNext();)
+        {
+          Method objectMethod = (Method) iter.next();
+          if (ProxyUtils.compareMethodOnNameAndParameterTypes(objectMethod,
+                                                              method))
+            {
+              expectObjectDeclaringClass = true;
+            }
+        }
+
+      harness.check((method.getDeclaringClass() == Object.class) == expectObjectDeclaringClass);
+
+      return ProxyUtils.getNeutralValue(method.getReturnType());
+    }
+
+  }
+
+  /**
+   * Interface redefining the same public non final methods as Object
+   */
+  private static interface WithObjectOverrides
+  {
+
+    public boolean equals(Object obj);
+
+    public int hashCode();
+
+    public String toString();
+
+  }
+
+  /**
+   * Interface redefining similar methods than Object
+   */
+  private static interface WithoutObjectOverrides
+  {
+    public boolean equals();
+
+    public long hashCode(Object obj);
+
+    public void toString(long foo);
+  }
+
+  /**
+   * Simple interface defining a method
+   */
+  private static interface Base
+  {
+    public void foo();
+  }
+
+  /**
+   * Simple interface overriding a non Object method
+   */
+  private static interface Derived extends Base
+  {
+    public void foo();
+  }
+
+}
Index: gnu/testlet/java/lang/reflect/Proxy/ProxyUtils.java
===================================================================
RCS file: gnu/testlet/java/lang/reflect/Proxy/ProxyUtils.java
diff -N gnu/testlet/java/lang/reflect/Proxy/ProxyUtils.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/testlet/java/lang/reflect/Proxy/ProxyUtils.java	19 Feb 2006 21:20:56 -0000
@@ -0,0 +1,133 @@
+/* ProxyUtils.java -- Utilities class for Proxy related operations
+ Copyright (C) 2006 Olivier Jolly <olivier.jolly@pcedev.com>
+ This file is part of Mauve.
+
+ Mauve is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Mauve is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Mauve; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ */
+
+// Tags: not-a-test
+
+
+package gnu.testlet.java.lang.reflect.Proxy;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+/**
+ * Utility class with some proxy related methods
+ * @author Olivier Jolly <olivier.jolly@pcedev.com>
+ */
+public final class ProxyUtils
+{
+
+  /**
+   * Compare two methods excepted the declaring class equality test
+   * @param lhs
+   *          first method to test
+   * @param rhs
+   *          second method to test
+   * @return whether the two methods are equals even if of different declaring
+   *         class
+   */
+  static boolean compareMethodExceptedDeclaringClass(Method lhs, Method rhs)
+  {
+    if (!lhs.getName().equals(rhs.getName()))
+      {
+        return false;
+      }
+    if (lhs.getReturnType() != rhs.getReturnType())
+      {
+        return false;
+      }
+    if (!Arrays.equals(lhs.getParameterTypes(), rhs.getParameterTypes()))
+      {
+        return false;
+      }
+    return true;
+  }
+
+  /**
+   * Compare two methods based only on their name and parameter
+   * @param lhs
+   *          first method to test
+   * @param rhs
+   *          second method to test
+   * @return whether the name and parameter type are equal
+   */
+  static boolean compareMethodOnNameAndParameterTypes(Method lhs, Method rhs)
+  {
+    if (!lhs.getName().equals(rhs.getName()))
+      {
+        return false;
+      }
+    if (!Arrays.equals(lhs.getParameterTypes(), rhs.getParameterTypes()))
+      {
+        return false;
+      }
+    return true;
+
+  }
+
+  /**
+   * Return a valid value for the given class, even if a primitive
+   * @param returnType
+   *          the expected class
+   * @return a neutral value of the expected class
+   * @throws InstantiationException
+   *           in case of problem with the constructor invocation
+   * @throws IllegalAccessException
+   *           in case of problem with the constructor invocation
+   */
+  public static Object getNeutralValue(Class returnType)
+      throws InstantiationException, IllegalAccessException
+  {
+    if (returnType.equals(boolean.class))
+      {
+        return Boolean.FALSE;
+      }
+    if (returnType.equals(int.class))
+      {
+        return new Integer(0);
+      }
+    if (returnType.equals(float.class))
+      {
+        return new Float(0);
+      }
+    if (returnType.equals(double.class))
+      {
+        return new Double(0);
+      }
+    if (returnType.equals(char.class))
+      {
+        return new Character((char) 0);
+      }
+    if (returnType.equals(short.class))
+      {
+        return new Short((short) 0);
+      }
+    if (returnType.equals(long.class))
+      {
+        return new Long(0);
+      }
+    if (returnType.equals(void.class))
+      {
+        return null;
+      }
+    return returnType.newInstance();
+  }
+
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]