/* 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.wonka.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(); } }