harmony-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Regis <xu.re...@gmail.com>
Subject Re: [classlib][luni] HashMap doesn't support proxy object as keys
Date Thu, 18 Jun 2009 07:55:10 GMT
Regis wrote:
> Jim Yu wrote:
>> Hi all,
>>
>> There is an interesting edge case in HashMap. If we use a proxy object as
>> the key to put something into HashMap, we will fail to retrieve the 
>> value by
>> using that key. But RI works well for this case. Here is a test case 
>> below
>> to present the problem. I found the root cause of the failure for our
>> HashMap is that proxyInstance.equals(proxyInstance) returns false which
>> sounds strange but appears work correctly as both Harmony and RI 
>> behave so.
> 
> It's very interesting behaviors, seems like RI did it intended, are 
> there any cases we need proxyInstance.equals(proxyInstance) return false?

I think TestProxy is not implemented very well. spec said:

"An invocation of the hashCode, equals, or toString methods declared in 
java.lang.Object on a proxy instance will be encoded and dispatched to the 
invocation handler's invoke method in the same manner as interface method 
invocations are encoded and dispatched, as described above. "

So Proxy.equals will be dispatched to TestProxy and then to MockClass, but the 
argument of this invocation is a proxy instance, it never equals a MockClass 
instance.

> 
>> I suspect RI has made some special approaches to match the key when 
>> the key
>> is a proxy object. So I would be inclined to follow RI's behavior in this
>> case. Any thoughts here?
> 
> I think if proxyInstance.equals(proxyInstance) return false is 
> reasonable, we should do some tricks to make HashMap work with Proxy. 
> And does Proxy object work well with other collections which used equals 
> to retrieve object from collection?

I tested ArrayList, Hashtable and HashSet:

         Map hm = new HashMap();
         hm.put(proxyInstance, proxyInstance);
         System.out.println(hm.containsKey(proxyInstance));
         System.out.println(hm.containsValue(proxyInstance));
         System.out.println();

         ArrayList<MockInterface> list = new ArrayList<MockInterface>();
         list.add(proxyInstance);
         System.out.println(list.contains(proxyInstance));
         System.out.println();

         Hashtable table = new Hashtable();
         table.put(proxyInstance, proxyInstance);
         System.out.println(table.containsKey(proxyInstance));
         System.out.println(table.containsValue(proxyInstance));
         System.out.println();

         HashSet set = new HashSet();
         set.add(proxyInstance);
         System.out.println(set.contains(proxyInstance));

the output of RI is:

true
false

false

false
false

true

seems RI doesn't use equals to retrieve keys in HashMap and values in HashSet.

> 
>>
>> I have raised a JIRA at
>> https://issues.apache.org/jira/browse/HARMONY-6237for this issue.
>>
>> public interface MockInterface {
>>     public String mockMethod();
>> }
>>
>> public class MockClass implements MockInterface {
>>     public String mockMethod() {
>>         return "This is a mock class.";
>>     }
>> }
>>
>> import java.lang.reflect.InvocationHandler;
>> import java.lang.reflect.Method;
>> import java.lang.reflect.Proxy;
>> import java.util.HashMap;
>> import java.util.Map;
>>
>> public class TestProxy implements InvocationHandler {
>>
>>     Object obj;
>>
>>     public TestProxy(Object o) {
>>         obj = o;
>>     }
>>
>>     public Object invoke(Object proxy, Method m, Object[] args)
>>             throws Throwable {
>>
>>         Object result = null;
>>
>>         try {
>>
>>             result = m.invoke(obj, args);
>>
>>         } catch (Exception e) {
>>             e.printStackTrace();
>>         } finally {
>>         }
>>         return result;
>>     }
>>
>>     public static void main(String[] argv) throws Exception {
>>
>>         MockInterface proxyInstance = (MockInterface)
>> Proxy.newProxyInstance(
>>                 MockInterface.class.getClassLoader(),
>>                 new Class[] { MockInterface.class }, new TestProxy(
>>                         new MockClass()));
>>
>>         Map hm = new HashMap();
>>
>>         hm.put(proxyInstance, "Value");
>>
>>         Object o = hm.get(proxyInstance);
>>
>>         System.out.println("Value got for proxy object key:" + o);
>>
>>         System.out.println(proxyInstance.equals(proxyInstance));
>>
>>     }
>> }
>>
>> Output
>> Harmony:
>> Value got for proxy object key:null
>> false
>>
>> RI:
>> Value got for proxy object key:Value
>> false
>>
> 
> 


-- 
Best Regards,
Regis.

Mime
View raw message