You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by Jim Yu <ju...@gmail.com> on 2009/06/18 08:52:44 UTC

[classlib][luni] HashMap doesn't support proxy object as keys

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.
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 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,
Jim, Jun Jie Yu

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by oleg babul <ol...@gmail.com>.
Sorry about this. I only wanted to show that the reason of different
behaviour isn't a proxy specific code.

Oleg

On Wed, Jul 8, 2009 at 12:17 PM, Tim Ellison<t....@gmail.com> wrote:
> On 08/Jul/2009 08:21, oleg babul wrote:
>> To find entry in the HashMap RI performs:
> <snip>
>
> Oleg, please don't post any code to the mailing list unless you authored
> it yourself and you are happy to grant an Apache license (ALv2) for us
> to use it.
>
> In particular, please don't post code or implementation details for code
> that is under other licenses without checking if it is ok first.
>
> Thanks,
> Tim
>
>

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Tim Ellison <t....@gmail.com>.
On 08/Jul/2009 08:21, oleg babul wrote:
> To find entry in the HashMap RI performs:
<snip>

Oleg, please don't post any code to the mailing list unless you authored
it yourself and you are happy to grant an Apache license (ALv2) for us
to use it.

In particular, please don't post code or implementation details for code
that is under other licenses without checking if it is ok first.

Thanks,
Tim


Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Sean Qiu <se...@gmail.com>.
If I'm correct, we're not suppose to investigate and discuss the
implementation details of RI.
Sounds it is violate our independent implemenation's goal.

Best Regards
Sean, Xiao Xia Qiu




2009/7/8 oleg babul <ol...@gmail.com>:
> To find entry in the HashMap RI performs:
> 1) Check that entry.hash==key.hashCode() (entry - hash map entry)
> 2) Check that entry.key == key or (key!=null && key.eqauls(entry.key))
>
> hm.get(proxyInstance); returns !=null object because entry.key == key
> in the 2) and equals doesn't perform.
>
> Oleg
>
> On Wed, Jul 8, 2009 at 8:34 AM, Regis<xu...@gmail.com> wrote:
>> Jim Yu wrote:
>>>
>>> 2009/6/18 Regis <xu...@gmail.com>
>>>
>>>> Jim Yu wrote:
>>>>
>>>>> 2009/6/18 Regis <xu...@gmail.com>
>>>>>
>>>>>  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 it is reasonable to return false here since spec mentioned for
>>>>> proxy
>>>>> instance that "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" So the meaning of
>>>>> equals method seems has been changed by the invoke here: )
>>>>>
>>>>>
>>>>>>  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?
>>>>>>
>>>>>>
>>>>> Agree. I have made a patch to do the trick so as to follow RI's
>>>>> behavior.
>>>>>
>>>> The patch looks good for me, applied at r786015, please verify.
>>>
>>>
>>> Verified at r786379.  Thanks, Regis.
>>>
>>>>
>>>>
>>>>>
>>>>>>  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.
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>> --
>>>> Best Regards,
>>>> Regis.
>>>>
>>>
>>>
>>>
>>
>> I found this patch involve serious performance regression. Because
>> Proxy.isProxyClass() synchronized on a instance "proxyCache", which is a
>> static field of Proxy, so all HashMap.get() will contend for this lock. So
>> is there other way to test whether a class is Proxy class or
>> Proxy.isProxyClass() could avoid to use lock of static field?
>>
>>
>> --
>> Best Regards,
>> Regis.
>>
>

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by oleg babul <ol...@gmail.com>.
To find entry in the HashMap RI performs:
1) Check that entry.hash==key.hashCode() (entry - hash map entry)
2) Check that entry.key == key or (key!=null && key.eqauls(entry.key))

hm.get(proxyInstance); returns !=null object because entry.key == key
in the 2) and equals doesn't perform.

Oleg

On Wed, Jul 8, 2009 at 8:34 AM, Regis<xu...@gmail.com> wrote:
> Jim Yu wrote:
>>
>> 2009/6/18 Regis <xu...@gmail.com>
>>
>>> Jim Yu wrote:
>>>
>>>> 2009/6/18 Regis <xu...@gmail.com>
>>>>
>>>>  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 it is reasonable to return false here since spec mentioned for
>>>> proxy
>>>> instance that "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" So the meaning of
>>>> equals method seems has been changed by the invoke here: )
>>>>
>>>>
>>>>>  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?
>>>>>
>>>>>
>>>> Agree. I have made a patch to do the trick so as to follow RI's
>>>> behavior.
>>>>
>>> The patch looks good for me, applied at r786015, please verify.
>>
>>
>> Verified at r786379.  Thanks, Regis.
>>
>>>
>>>
>>>>
>>>>>  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.
>>>>>
>>>>>
>>>>
>>>>
>>> --
>>> Best Regards,
>>> Regis.
>>>
>>
>>
>>
>
> I found this patch involve serious performance regression. Because
> Proxy.isProxyClass() synchronized on a instance "proxyCache", which is a
> static field of Proxy, so all HashMap.get() will contend for this lock. So
> is there other way to test whether a class is Proxy class or
> Proxy.isProxyClass() could avoid to use lock of static field?
>
>
> --
> Best Regards,
> Regis.
>

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Regis <xu...@gmail.com>.
Jim Yu wrote:
> 2009/6/18 Regis <xu...@gmail.com>
> 
>> Jim Yu wrote:
>>
>>> 2009/6/18 Regis <xu...@gmail.com>
>>>
>>>  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 it is reasonable to return false here since spec mentioned for
>>> proxy
>>> instance that "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" So the meaning of
>>> equals method seems has been changed by the invoke here: )
>>>
>>>
>>>>  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?
>>>>
>>>>
>>> Agree. I have made a patch to do the trick so as to follow RI's behavior.
>>>
>> The patch looks good for me, applied at r786015, please verify.
> 
> 
> Verified at r786379.  Thanks, Regis.
> 
>>
>>
>>>
>>>>  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.
>>>>
>>>>
>>>
>>>
>> --
>> Best Regards,
>> Regis.
>>
> 
> 
> 

I found this patch involve serious performance regression. Because 
Proxy.isProxyClass() synchronized on a instance "proxyCache", which is a static 
field of Proxy, so all HashMap.get() will contend for this lock. So is there 
other way to test whether a class is Proxy class or Proxy.isProxyClass() could 
avoid to use lock of static field?


-- 
Best Regards,
Regis.

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Jim Yu <ju...@gmail.com>.
2009/6/18 Regis <xu...@gmail.com>

> Jim Yu wrote:
>
>> 2009/6/18 Regis <xu...@gmail.com>
>>
>>  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 it is reasonable to return false here since spec mentioned for
>> proxy
>> instance that "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" So the meaning of
>> equals method seems has been changed by the invoke here: )
>>
>>
>>>  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?
>>>
>>>
>> Agree. I have made a patch to do the trick so as to follow RI's behavior.
>>
>
> The patch looks good for me, applied at r786015, please verify.


Verified at r786379.  Thanks, Regis.

>
>
>
>>
>>
>>>  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.
>>>
>>>
>>
>>
>>
>
> --
> Best Regards,
> Regis.
>



-- 
Best Regards,
Jim, Jun Jie Yu

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Regis <xu...@gmail.com>.
Jim Yu wrote:
> 2009/6/18 Regis <xu...@gmail.com>
> 
>> 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 it is reasonable to return false here since spec mentioned for proxy
> instance that "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" So the meaning of
> equals method seems has been changed by the invoke here: )
> 
>>
>>  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?
>>
> 
> Agree. I have made a patch to do the trick so as to follow RI's behavior.

The patch looks good for me, applied at r786015, please verify.

> 
> 
>>
>>> 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.
>>
> 
> 
> 


-- 
Best Regards,
Regis.

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Jim Yu <ju...@gmail.com>.
2009/6/18 Regis <xu...@gmail.com>

> 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 it is reasonable to return false here since spec mentioned for proxy
instance that "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" So the meaning of
equals method seems has been changed by the invoke here: )

>
>
>  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?
>

Agree. I have made a patch to do the trick so as to follow RI's behavior.


>
>
>> 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.
>



-- 
Best Regards,
Jim, Jun Jie Yu

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Jim Yu <ju...@gmail.com>.
2009/6/18 Regis <xu...@gmail.com>

> 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.


Sounds interesting. It seems RI does use a special key matching mechanism
for the HashMap if the key is proxy object. As HashSet is implemented based
on HashMap, it is reasonable that HashSet will behave in the same way. And
We will follow RI's behavior of HashSet as well after applying my patch for
the HashMap.


>
>
>
>>
>>> 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.
>



-- 
Best Regards,
Jim, Jun Jie Yu

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Regis <xu...@gmail.com>.
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.

Re: [classlib][luni] HashMap doesn't support proxy object as keys

Posted by Regis <xu...@gmail.com>.
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 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 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.