unintuitive hashCode() of java proxies

NEW
Unassigned

Status

Core Graveyard
Java to XPCOM Bridge
12 years ago
3 years ago

People

(Reporter: Michal Ceresna, Unassigned)

Tracking

(Depends on: 1 bug)

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment)

(Reporter)

Description

12 years ago
User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060614 Fedora/1.5.0.4-1.2.fc5 Firefox/1.5.0.4 pango-text
Build Identifier: 

reposted from mailing list:
http://groups.google.com/group/mozilla.dev.tech.java/browse_thread/thread/96515e7806497bcf/457f96a448573e44#457f96a448573e44


this code fails:

nsIDOMElement div1 = document.createElement("div");
nsIDOMNode div2 = div1.queryInterface(nsIDOMNode.NS_IDOMNODE_IID);
assert div1.hashCode()==div2.hasCode()

Intuitively, the hashCode should be equal, if the underlying native
object is the same.


Reproducible: Always
This is a known issue which cannot easily be fixed (suggestions are welcome!).  It deals with how I implemented Java proxies for XPCOM objects.  To illustrate, I'll explain how the Java proxies are handled for the provided example code:

> nsIDOMElement div1 = document.createElement("div");

The underlying C++ method for "createElement" returns an XPCOM object which implements many interfaces, one of which is nsIDOMElement.  In order for the object to be useful to Java, JavaXPCOM creates a Java Proxy for the object.  The proxy implements nsIDOMElement.

> nsIDOMNode div2 = div1.queryInterface(nsIDOMNode.NS_IDOMNODE_IID);

In this case, the underlying C++ method returns the same object.  JavaXPCOM checks to see if a Java proxy already exists for this object.  One does, but for the interface nsIDOMElement; this method needs to return a proxy for nsIDOMNode.  So JavaXPCOM creates a _new_ Java Proxy, this one implementing nsIDOMNode.

> assert div1.hashCode()==div2.hasCode()

This fails because on the Java side, div1 and div2 are actually different objects, but they both represent the same XPCOM object.

One solution to this problem would be for JavaXPCOM to create a Java proxy with all of the XPCOM objects interfaces.  While Mozilla does provide an interface, called nsIClassInfo, that can be queried for all of the implemented interfaces, few classes actually implement it.  So this solution isn't feasible.

The other solution would be to add interfaces to the Java proxy as they become known.  Unfortunately, Java's Proxy class doesn't allow this (once it is created, the Proxy's interfaces are static), nor have I found a solution that would allow this.
(Reporter)

Comment 2

12 years ago
What would be wrong with a code like this:

go to native code
take JavaXPCOMInstance->GetInstance()
queryInterface it to nsISupports
and return the nsISupports* pointer as hashCode
Actually, that might work.  I was thinking that I needed the actual hashcode for the Java Proxy to get its associated XPCOM object.  But this is only true for going from a real Java object to an XPCOM proxy.  The Java Proxy used by JavaXPCOM already has a pointer to the real XPCOM object.

I'll come up with a patch for this.
Status: UNCONFIRMED → NEW
Ever confirmed: true
There might be a problem with that solution.  If the hash code is determined by the Java proxy's referent, then you have the possibility of multiple Java objects, which all represent the same XPCOM object, having the same hash code.  This may lead to unintended consequences.
(Reporter)

Comment 5

12 years ago
(In reply to comment #4)
> There might be a problem with that solution.  If the hash code is determined by
> the Java proxy's referent, then you have the possibility of multiple Java
> objects, which all represent the same XPCOM object, having the same hash code. 
> This may lead to unintended consequences.

What do you exactly mean by "Java proxy's referent"?

According to javadoc http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#hashCode()
the following rule has to be fulfilled:
  if A.equals(B) then A.hasCode()==B.hashCode()

The inverse implication
  if !A.equals(B) then A.hasCode()!=B.hashCode()
is not required. 

Thus, it is fine for different (not-equal) java objects return
the same hashCode.
(In reply to comment #5)
> What do you exactly mean by "Java proxy's referent"?

Sorry, I'm confusing myself.  That's weak reference terminology.  What I meant by that was "the XPCOM object that the Java proxy wraps".

>   if A.equals(B) then A.hasCode()==B.hashCode()

But in this case, A and B are not equal.  They are two different Proxy instances which implement different interfaces, although they wrap the same XPCOM object.

Comment 7

12 years ago
> But in this case, A and B are not equal. They are two different Proxy
> instances which implement different interfaces

I don't care Proxy itself is same or not, because Java, C++, XPCOM use
different RTTI, you can't use Java concept on XPCOM, just like RMI or
CORBA, for examples, java.rmi.server.RemoteObject or org.omg.CORBA.portable.ObjectImpl...
(In reply to comment #6)
> But in this case, A and B are not equal.  They are two different Proxy
> instances which implement different interfaces, although they wrap the same
> XPCOM object.

But it's fine for different instances to map to the same hash code. That's just a hash collision then.

Updated

11 years ago
Depends on: 380296
Once bug 380296 is fixed, XPCOMJavaProxy's |nativeXPCOMPtr| member will point directly to the native object, and we can do something like |new Long(nativeXPCOMPtr).hashCode()|.
Created attachment 264794 [details] [diff] [review]
patch

This patch creates the hash code for the Proxy based on the associated native object.  Also cleans up some things in XPCOMJavaProxy, based on the patch from bug 380296.

Updated

4 years ago
Assignee: jhpedemonte → nobody
(Assignee)

Updated

3 years ago
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.