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


##########
dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java:
##########
@@ -176,7 +182,7 @@ public Map<String, String> getMetadata() {
 
     @Override
     public SortedMap<String, String> getSortedMetadata() {
-        return new TreeMap<>(getMetadata());
+        return metadata;

Review Comment:
   Returning the internal metadata field directly breaks encapsulation and 
allows external modification of the internal state. Consider returning a copy 
or an unmodifiable view: Collections.unmodifiableSortedMap(metadata).
   ```suggestion
           return Collections.unmodifiableSortedMap(metadata);
   ```



##########
dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java:
##########
@@ -305,28 +315,61 @@ 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)) {
+        if (!Objects.equals(getServiceName(), that.getServiceName())
+                || !Objects.equals(getHost(), that.getHost())
+                || !Objects.equals(getPort(), that.getPort())) {
+            return false;
+        }
+
+        // compare map entry values by iterating over two sorted metadata maps 
in a single pass.
+        Iterator<Map.Entry<String, String>> iterThis =
+                this.getSortedMetadata().entrySet().iterator();
+        Iterator<Map.Entry<String, String>> iterThat =
+                that.getSortedMetadata().entrySet().iterator();
+
+        boolean hasNext = iterThis.hasNext();
+        if (hasNext != iterThat.hasNext()) {
+            // keep consistency with hashCode, as any extra or less key would 
result in a different hashCode.
+            return false;
+        }
+
+        while (hasNext) {
+            Map.Entry<String, String> entryThis = iterThis.next();
+            Map.Entry<String, String> entryThat = iterThat.next();
+
+            String key = entryThis.getKey();
+            if (!key.equals(entryThat.getKey())) {
+                // keep consistency with hashCode, as any extra or less key 
would result in a different hashCode.
+                return false;
+            }
+
+            if (key.equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME) || 
key.equals(TIMESTAMP_KEY)) {
+                // skip entry value comparison.
                 continue;
             }
-            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 (!Objects.equals(entryThis.getValue(), entryThat.getValue())) {
+                return false;
+            }
+
+            hasNext = iterThis.hasNext();
+            if (hasNext != iterThat.hasNext()) {
+                // keep consistency with hashCode, as any extra or less key 
would result in a different hashCode.
+                return false;
             }
         }
 
-        return equals;
+        return true;

Review Comment:
   [nitpick] The iterator-based comparison is unnecessarily complex for this 
use case. Since both maps are now TreeMaps with the same ordering, you could 
simply compare the filtered maps directly using Objects.equals() after removing 
the excluded keys, which would be more readable and maintainable.



##########
dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java:
##########
@@ -57,7 +60,10 @@ public class DefaultServiceInstance implements 
ServiceInstance {
 
     private boolean healthy = true;
 
-    private Map<String, String> metadata = new HashMap<>();
+    /**
+     * use SortedMap to ensure the hashCode of metadata will be calculated by 
the same order
+     */
+    private SortedMap<String, String> metadata = new TreeMap<>();

Review Comment:
   Changing the field type from Map to SortedMap is a breaking API change. This 
could cause compilation errors for code that directly accesses this field or 
relies on the specific Map implementation. Consider keeping the field as 
Map<String, String> while internally using TreeMap implementation.
   ```suggestion
       private Map<String, String> metadata = new TreeMap<>();
   ```



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