Groups | Blog | Home
all groups > vj# > january 2005 >

vj# : InetAddress.equals() Anomoly?


Pete Loveall
1/6/2005 9:56:08 AM
Can someone (at Microsoft) tell me how the J# implementation of
InetAddress.equals(Object) works (Java version of equals)? Does it do a
byte wise comparison of the address as stated in the Java API (and as it
does in the Windows JVM) or does it do a simple toString() comparison?

I have a situation where it seems that it may be doing a String comparison
instead of an address comparison. This is bad considering that .NET appears
to do a reverse DNS lookup (also bad) on inbound connections and the reverse
DNS name may not (usually does not) match the DNS name used in the program.
This would be especially problematic with dynamic DNS systems.

I would post some test code, but I can't directly reproduce the problem
because my test program is doing a reverse DNS on the InetAddress returned
by InetAddress.getByName("..."). However, I have a program up and running
which displays the reverse DNS for one outbound connection but not for
another yet both used the same InetAddress.getByName("") method. I don't
understand why that would happen, either.

This is seen on .NET and J# 1.1.4322

Pete Loveall

Pete Loveall
1/6/2005 7:31:15 PM
Per the MSDN Online Library:

InetAddress.equals
Syntax
public boolean equals( Object obj )
Parameters
obj
the object to compare against.
Returns
true if the objects are the same; false otherwise.
Description
Compares this object against the specified object. The result is true if and
only if the argument is not null and it represents the same IP address as
this object.
Two instances of InetAddress represent the same IP address if the length of
the byte arrays returned by getAddress is the same for both, and each of the
array components is the same for the byte arrays.
Overrides
equals in class Object

My problem is regarding a Hashtable lookup. If J# is doing the equals
correctly (which I have not been able to check), could it be doing the
hashCode incorrectly?

[quoted text, click to view]
Pete Loveall
1/7/2005 9:49:59 AM
Definite J# bug!

The following output was produced by the code below:

203574117 203574117
firenet.us/12.34.75.101=grande.rivcom.net/12.34.75.101->false
grande.rivcom.net/12.34.75.101=firenet.us/12.34.75.101->false

import java.net.*;

public class Class1
{
public Class1()
{
}
/** @attribute System.STAThread() */
public static void main(String[] args)
{
InetAddress dnsaddr = null;
InetAddress ipaddr = null;
try
{
dnsaddr = InetAddress.getByName("firenet.us");
ipaddr = InetAddress.getByName("12.34.75.101");
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(dnsaddr.hashCode()+" "+ipaddr.hashCode());
System.out.println(dnsaddr.toString()+"="+ipaddr.toString()+"->"+dnsaddr.equals(ipaddr));
System.out.println(ipaddr.toString()+"="+dnsaddr.toString()+"->"+ipaddr.equals(dnsaddr));
try
{
System.in.read();
}
catch (Exception e){}
}
}

Bruno Jouhier [MVP]
1/8/2005 9:31:14 AM
I don't agree.

Two objects are equal if they can be used interchangeably and if they
produce the same results when any arbitrary method is applied to them.

In your case:
dnsaddr.toString() produces firenet.us/12.34.75.101
ipaddr.toString() produces grande.rivcom.net/12.34.75.101

So, the objects are not equal because they don't produce the same result
when you apply toString() to them.

If you consider that two InetAddress should be equal as soon as they have
the same IP, you take a biased view, you consider that your equals method
should take the IP part into account and completely ignore the name side of
the INetAddress object. This is wrong. If you start overriding equals to
give it "partially equals" semantics, you are going to run into some
trouble.

So, this is not a bug in the JDK. If you want to use the IP as a hash key,
you should use the IP (formatted as a string, or as an integer) as key, you
should not use InetAddress because this is a richer object that carries more
information than an IP.

Bruno.


"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news:
ePrGKCN9EHA.1296@TK2MSFTNGP10.phx.gbl...
[quoted text, click to view]

Pete Loveall
1/8/2005 12:15:52 PM
As shown in my follow-up post, this is not a matter of opinion! ALL Java
API documents (including Microsoft's) state:

Compares this object against the specified object. The result is true if and
only if the argument is not null and it represents the same IP address as
this object.
Two instances of InetAddress represent the same IP address if the length of
the byte arrays returned by getAddress is the same for both, and each of the
array components is the same for the byte arrays.

This says nothing about toString(). In fact, it specifically states that
ONLY the IP address is to be considered when doing the comparison, NOT the
DNS name or any other mangled name that the JVM might come up with.

Pete Loveall

[quoted text, click to view]

Pete Loveall
1/8/2005 12:37:15 PM
BTW, the quote in my post was taken from the MSDN Online Library for
InetAddress.equals()
http://msdn.microsoft.com/library/en-us/vjref98/html/java.net.InetAddress007.asp
If J# is to be compatible with Java 1.1.4 (Microsoft's JVM), then areas of
direct incompatibility such as this are bugs in J#. They break working
programs.

It is a major mistake to think that comparing toString() methods (or any
other method, for that matter) for any object provides proper equals()
operation. If the Java API implements equals() for an object, then J# must
use the same general implementation or it risks (as in this case) breaking
working programs with incorrect results.

Your "definition" of two objects being equal has no basis in the Java API.
I refer you to any Java API documenet on Object.equals() for a proper
definition
http://msdn.microsoft.com/library/en-us/vjref98/html/java.lang.Object005.asp
hashCode() must also obey the same rules as equals() with the exception that
two objects with the same hashCode can fail equals(), but two objects that
pass equals() MUST have the same hashCode. In the case of InetAddress, the
hashCode appears to be computed correctly by J#.

Pete Loveall

[quoted text, click to view]

Pete Loveall
1/9/2005 8:02:31 AM
[quoted text, click to view]

The specs are not "wrong", they are simply in conflict with what your think
they should be. The Java spec for object equality was written in the very
earliest of development of the Java language to be able to handle specific
issues such as this.

The original specification for InetAddress says nothing about the format of
the toString() method. For that matter, different JVM's have implemented
toString() in a variety of ways. J# is the only "JVM", by the way, which
converts DNS names to conical DNS names if the DNS server returns that, and
does reverse DNS lookups on every connection. InetAddress is exactly what
its name implies: a holder for an Internet address, otherwise known as an IP
address. All of the members relate to the IP address, not the DNS (or
reverse DNS) name. Even getHostName() will return the local computer's
"name" if the InetAddress does not have a DNS name stored in it. This focus
on IP address has made it possible for Sun to derive IPv4 and IPv6 classes
which can be used interchangeably in existing or new programs written with
no IPv4 vs. IPv6 awareness. Quite forward thinking, if you ask me.

The Java language accounted for variances in class use, such as this, and in
the process made a very flexible programming language. If the creator of a
class says "this is what this class is for", then the creator can make all
relevant overrides to reflect that. Should the class have some ancillary
capabilities which do not affect the primary purpose of the class, then
those ancillary capabilities can safely be ignored when considering object
equality. It is a different viewpoint from yours, but it is the viewpoint
that is written into the Java specification and should be readily understood
and accepted by anyone writing Java or J# applications.

Peter Loveall

Bruno Jouhier [MVP]
1/9/2005 10:50:25 AM

"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news:
%23zrNW4a9EHA.2196@TK2MSFTNGP14.phx.gbl...
[quoted text, click to view]


If the specs says that then:

1) The J# implementation is buggy because it does not follow the specs.

2) The specs are bad because they violate the normal semantics of "equals".

But I agree with you, point 1) should prevail then and the J# guys should
fix the implementation so that it conforms to the specs (even if the specs
are wrong).

[quoted text, click to view]

Bruno Jouhier [MVP]
1/9/2005 10:59:58 AM

"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news:
%23%23wRTEb9EHA.3708@TK2MSFTNGP14.phx.gbl...
[quoted text, click to view]

I am not saying that:
if the values returned by toString() are equal, then the objects are
equal.
I am saying that:
if the objects are equal, then the values obtained with toString()
should be equal

So I am not saying that toString() provides proper equals() semantics, I am
saying something very different (and much stronger).

[quoted text, click to view]

Agree!

[quoted text, click to view]

Yes, unfortunately. The Java specs leave room for implementations that
correspond to "partially equals" semantics. IMO, this is wrong, but you are
right that these are the specs and we have to live with them.

Bruno.

[quoted text, click to view]

Bruno Jouhier [MVP]
1/9/2005 11:40:41 AM
One more note on this equals issue:

The JDK is rather inconsistent in the way it treats "equals".

In most cases, it implements a very strict form of equals, i.e., one that
follows my definition (all methods will return the same result if two
objects are equal). The typical example is "Double":

+0.0d == -0.0d is true
but new Double(+0.0d).equals(new Double(-0.0d)) is false!

You have to do this if you want all methods, including
Double.doubleToLongBits(d.doubleValue()) to return the same result when two
objects are equal. But they could have chosen a looser version in which new
Double(0.0d) and new Double(-0.0d) are equal, without breaking the
Object.equals specs.

So, I was wrong in assuming too quickly that the JDK was always using the
strict interpretation of equals. This is obviously not the case with
INetAddr.

Also, in all my implementations around hashtables, I avoid mutable keys and
keys with "partially equals" semantics because they are a source of
confusions (and bugs, think of what happens if a mutable key is modified
after being stored in the hash table). I stick to "immutable" objects with
very strict equals and hashcode semantics (String, Integer or immutable
classes of my own). So, I never hit this kind of problem.

Bruno.

Bruno Jouhier [MVP]
1/9/2005 5:23:32 PM

"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news:
ObDpbPl9EHA.2876@TK2MSFTNGP12.phx.gbl...
[quoted text, click to view]

I was completely wrong here. I have only worked occasionnaly with the
java.net API and I naively thought that InetAddress was keeping track of the
IP/Name combination (and I was misled by the toString() example). So, this
is why I thought that giving focus on the IP side for equals was wrong. If
the intent of INetAddress is only to encapsulate the IP side, then it makes
perfect sense to override equals as defined by the specs.

[quoted text, click to view]

Ok. Again, I was under the impression that INetAddress was encapsulating an
IP/Name combination, and it is not, it is just an IP (and the fact that the
name is added by toString() is just a convenience).

[quoted text, click to view]

AddThis Social Bookmark Button