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