Copilot commented on code in PR #15633:
URL: https://github.com/apache/dubbo/pull/15633#discussion_r2280341945


##########
dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java:
##########
@@ -305,28 +310,77 @@ public boolean equals(Object o) {
             return false;
         }
         DefaultServiceInstance that = (DefaultServiceInstance) o;
-        boolean equals = Objects.equals(getServiceName(), 
that.getServiceName())
-                && Objects.equals(getHost(), that.getHost())
-                && Objects.equals(getPort(), that.getPort());
-        for (Map.Entry<String, String> entry : this.getMetadata().entrySet()) {
-            if 
(entry.getKey().equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME)) {
-                continue;
+        if (!Objects.equals(serviceName, that.serviceName)
+                || !Objects.equals(host, that.host)
+                || !Objects.equals(port, that.port)) {
+            return false;
+        }
+
+        // compare metadata.
+        return compareMetadata(that.metadata);
+    }
+
+    /**
+     * Compares this instance's metadata with another {@code SortedMap<String, 
String>} for equality.
+     * <p>
+     * The comparison is performed in key order. For each key:
+     * <ul>
+     *   <li>If the key is EXPORTED_SERVICES_REVISION_PROPERTY_NAME or 
TIMESTAMP_KEY,
+     *       only the presence and order of the key are checked; their values 
are ignored.</li>
+     *   <li>For all other keys, both the key and its value must match.</li>
+     * </ul>
+     * <p>
+     * This method is designed to ensure consistency with the {@code hashCode} 
implementation,
+     * as indicated by the inline comments. Any difference in key presence, 
order, or (for non-excluded keys) value
+     * will result in {@code false}.
+     *
+     * @param thatMetadata the metadata map to compare with
+     * @return {@code true} if the metadata maps are considered equal 
according to the above rules; {@code false} otherwise
+     */
+    private boolean compareMetadata(SortedMap<String, String> thatMetadata) {
+        Iterator<Map.Entry<String, String>> thisIter = 
this.metadata.entrySet().iterator();
+        Iterator<Map.Entry<String, String>> thatIter = 
thatMetadata.entrySet().iterator();
+
+        boolean hasNext = thisIter.hasNext();
+        if (hasNext != thatIter.hasNext()) {
+            // hashCode will be different if there are an extra or less key 
between two metadata.
+            return false;
+        }
+
+        while (hasNext) {
+            Map.Entry<String, String> thisEntry = thisIter.next();
+            Map.Entry<String, String> thatEntry = thatIter.next();
+
+            String key = thisEntry.getKey();
+            if (!key.equals(thatEntry.getKey())) {
+                // hashCode will be different if there are an extra or less 
key between two metadata.
+                return false;
             }
-            if (entry.getValue() == null) {
-                equals = equals && (entry.getValue() == 
that.getMetadata().get(entry.getKey()));
-            } else {
-                equals = equals && 
entry.getValue().equals(that.getMetadata().get(entry.getKey()));
+
+            if (!key.equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME) && 
!key.equals(TIMESTAMP_KEY)) {
+                if (!Objects.equals(thisEntry.getValue(), 
thatEntry.getValue())) {
+                    return false;
+                }
+            }
+
+            hasNext = thisIter.hasNext();
+            if (hasNext != thatIter.hasNext()) {
+                // hashCode will be different if there are an extra or less 
key between two metadata.
+                return false;
             }
         }
 
-        return equals;
+        return true;
     }
 
     @Override
     public int hashCode() {
         int result = Objects.hash(getServiceName(), getHost(), getPort());
-        for (Map.Entry<String, String> entry : this.getMetadata().entrySet()) {
-            if 
(entry.getKey().equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME)) {
+
+        // use SortedMap as metadata type to ensure the hashCode calculation 
is consistent with equals method.
+        for (Map.Entry<String, String> entry : this.metadata.entrySet()) {
+            String key = entry.getKey();
+            if (key.equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME) || 
key.equals(TIMESTAMP_KEY)) {
                 continue;
             }
             result = 31 * result

Review Comment:
   The hashCode calculation is incomplete. The line appears to be cut off and 
doesn't include the actual hash contribution from the metadata entry.



##########
dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java:
##########
@@ -305,28 +310,77 @@ public boolean equals(Object o) {
             return false;
         }
         DefaultServiceInstance that = (DefaultServiceInstance) o;
-        boolean equals = Objects.equals(getServiceName(), 
that.getServiceName())
-                && Objects.equals(getHost(), that.getHost())
-                && Objects.equals(getPort(), that.getPort());
-        for (Map.Entry<String, String> entry : this.getMetadata().entrySet()) {
-            if 
(entry.getKey().equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME)) {
-                continue;
+        if (!Objects.equals(serviceName, that.serviceName)
+                || !Objects.equals(host, that.host)
+                || !Objects.equals(port, that.port)) {
+            return false;
+        }
+
+        // compare metadata.
+        return compareMetadata(that.metadata);
+    }
+
+    /**
+     * Compares this instance's metadata with another {@code SortedMap<String, 
String>} for equality.
+     * <p>
+     * The comparison is performed in key order. For each key:
+     * <ul>
+     *   <li>If the key is EXPORTED_SERVICES_REVISION_PROPERTY_NAME or 
TIMESTAMP_KEY,
+     *       only the presence and order of the key are checked; their values 
are ignored.</li>
+     *   <li>For all other keys, both the key and its value must match.</li>
+     * </ul>
+     * <p>
+     * This method is designed to ensure consistency with the {@code hashCode} 
implementation,
+     * as indicated by the inline comments. Any difference in key presence, 
order, or (for non-excluded keys) value
+     * will result in {@code false}.
+     *
+     * @param thatMetadata the metadata map to compare with
+     * @return {@code true} if the metadata maps are considered equal 
according to the above rules; {@code false} otherwise
+     */
+    private boolean compareMetadata(SortedMap<String, String> thatMetadata) {
+        Iterator<Map.Entry<String, String>> thisIter = 
this.metadata.entrySet().iterator();
+        Iterator<Map.Entry<String, String>> thatIter = 
thatMetadata.entrySet().iterator();
+
+        boolean hasNext = thisIter.hasNext();
+        if (hasNext != thatIter.hasNext()) {
+            // hashCode will be different if there are an extra or less key 
between two metadata.
+            return false;
+        }
+
+        while (hasNext) {
+            Map.Entry<String, String> thisEntry = thisIter.next();
+            Map.Entry<String, String> thatEntry = thatIter.next();
+
+            String key = thisEntry.getKey();
+            if (!key.equals(thatEntry.getKey())) {
+                // hashCode will be different if there are an extra or less 
key between two metadata.
+                return false;
             }
-            if (entry.getValue() == null) {
-                equals = equals && (entry.getValue() == 
that.getMetadata().get(entry.getKey()));
-            } else {
-                equals = equals && 
entry.getValue().equals(that.getMetadata().get(entry.getKey()));
+
+            if (!key.equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME) && 
!key.equals(TIMESTAMP_KEY)) {
+                if (!Objects.equals(thisEntry.getValue(), 
thatEntry.getValue())) {
+                    return false;
+                }
+            }
+
+            hasNext = thisIter.hasNext();
+            if (hasNext != thatIter.hasNext()) {
+                // hashCode will be different if there are an extra or less 
key between two metadata.
+                return false;
             }
         }
 
-        return equals;
+        return true;
     }

Review Comment:
   [nitpick] The compareMetadata method is overly complex and contains 
duplicate logic for checking iterator states. Consider simplifying by using a 
more straightforward approach that filters out excluded keys first, then 
compares the remaining entries directly.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org
For additional commands, e-mail: notifications-h...@dubbo.apache.org

Reply via email to