diff --git a/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java b/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java index aab42833..89a6ad7e 100644 --- a/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java +++ b/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java @@ -20,6 +20,7 @@ package org.apache.ivy.core.module.id; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -259,7 +260,7 @@ public class ModuleRevisionId extends UnmodifiableExtendableItem { public String encodeToString() { StringBuilder buf = new StringBuilder(); - Map attributes = new HashMap<>(getAttributes()); + Map attributes = new TreeMap<>(getAttributes()); attributes.keySet().removeAll(getExtraAttributes().keySet()); attributes.putAll(getQualifiedExtraAttributes()); diff --git a/test/java/org/apache/ivy/core/module/id/ModuleRevisionIdTest.java b/test/java/org/apache/ivy/core/module/id/ModuleRevisionIdTest.java index 9a7667e6..5af34d4f 100644 --- a/test/java/org/apache/ivy/core/module/id/ModuleRevisionIdTest.java +++ b/test/java/org/apache/ivy/core/module/id/ModuleRevisionIdTest.java @@ -85,6 +85,12 @@ public class ModuleRevisionIdTest { extraAttributes.put("nullatt", null); testEncodeDecodeToString( ModuleRevisionId.newInstance("org/apache", "pre/name", "1.0-dev8/2", extraAttributes)); + + String encoded = ModuleRevisionId.newInstance("org/apache", "pre/name", "1.0-dev8/2", extraAttributes).encodeToString(); + // We expect the encoding/ordering to be stable for reproducibility. + // If necessary this may vary across Ivy versions, + // but ideally only intentionally. + assertEquals("+att.name:#@#:+att.value:#@#:+att/name:#@#:+att/value:#@#:+att