all groups > vj# > january 2005 >
vj# :
InetAddress.equals() Anomoly?
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
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" wrote: > 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?
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){} } }
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] > 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){} > } > } > >
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] "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message news:OvNeuxV9EHA.2568@TK2MSFTNGP11.phx.gbl... >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.
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] > "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message > news:OvNeuxV9EHA.2568@TK2MSFTNGP11.phx.gbl... >>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. > >
[quoted text, click to view] "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message news:O1zEqCj9EHA.1188@tk2msftngp13.phx.gbl... > > 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).
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
"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news: %23zrNW4a9EHA.2196@TK2MSFTNGP14.phx.gbl... [quoted text, click to view] > 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. >
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] > Pete Loveall > > "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message > news:OvNeuxV9EHA.2568@TK2MSFTNGP11.phx.gbl... >>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: %23%23wRTEb9EHA.3708@TK2MSFTNGP14.phx.gbl... [quoted text, click to view] > 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. 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] > 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.
Agree! [quoted text, click to view] > > 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#. 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] > > Pete Loveall > >> "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message >> news:OvNeuxV9EHA.2568@TK2MSFTNGP11.phx.gbl... >>>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. >> >> > >
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.
"Pete Loveall" <psl@ametx.com.NO_SPAM> a écrit dans le message de news: ObDpbPl9EHA.2876@TK2MSFTNGP12.phx.gbl... [quoted text, click to view] > "Bruno Jouhier [MVP]" <bjouhier@club-internet.fr> wrote in message > news:O1zEqCj9EHA.1188@tk2msftngp13.phx.gbl... >> >> 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). > > 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.
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] > > 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.
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] > > Peter Loveall >
Don't see what you're looking for? Try a search.
|
|
|