Fix Map key collision

This commit is contained in:
HeshamHM28 2026-01-30 18:36:48 +02:00
parent a4ee9ebf4d
commit 1e0236bbe0
2 changed files with 62 additions and 1 deletions

View file

@ -16,6 +16,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
@ -256,6 +257,7 @@ public final class Serializer {
private static JsonElement serializeMap(Map<?, ?> map, IdentityHashMap<Object, Boolean> seen, int depth) {
JsonObject jsonObject = new JsonObject();
Map<String, Integer> keyCount = new HashMap<>();
int count = 0;
for (Map.Entry<?, ?> entry : map.entrySet()) {
@ -263,7 +265,8 @@ public final class Serializer {
jsonObject.addProperty("__truncated__", map.size() - count + " more entries");
break;
}
String key = entry.getKey() != null ? entry.getKey().toString() : "null";
String baseKey = entry.getKey() != null ? entry.getKey().toString() : "null";
String key = getUniqueKey(baseKey, keyCount);
jsonObject.add(key, serialize(entry.getValue(), seen, depth + 1));
count++;
}
@ -311,4 +314,16 @@ public final class Serializer {
return clazz.getName();
}
/**
* Get a unique key for map serialization, appending _N suffix for duplicates.
*/
private static String getUniqueKey(String baseKey, Map<String, Integer> keyCount) {
int count = keyCount.getOrDefault(baseKey, 0);
keyCount.put(baseKey, count + 1);
if (count == 0) {
return baseKey;
}
return baseKey + "_" + count;
}
}

View file

@ -251,6 +251,52 @@ class SerializerTest {
}
}
@Nested
@DisplayName("Map Key Collision")
class MapKeyCollisionTests {
@Test
@DisplayName("should handle duplicate toString keys without losing data")
void testDuplicateToStringKeys() {
Map<Object, String> map = new LinkedHashMap<>();
map.put(new SameToString("A"), "first");
map.put(new SameToString("B"), "second");
String json = Serializer.toJson(map);
// Both values should be present, not overwritten
assertTrue(json.contains("first"), "First value should be present, got: " + json);
assertTrue(json.contains("second"), "Second value should be present, got: " + json);
}
@Test
@DisplayName("should append index to duplicate keys")
void testDuplicateKeysGetIndex() {
Map<Object, String> map = new LinkedHashMap<>();
map.put(new SameToString("A"), "first");
map.put(new SameToString("B"), "second");
map.put(new SameToString("C"), "third");
String json = Serializer.toJson(map);
// Should have same-key, same-key_1, same-key_2
assertTrue(json.contains("\"same-key\""), "Original key should be present");
assertTrue(json.contains("\"same-key_1\""), "First duplicate should have _1 suffix");
assertTrue(json.contains("\"same-key_2\""), "Second duplicate should have _2 suffix");
}
}
static class SameToString {
String internalValue;
SameToString(String value) {
this.internalValue = value;
}
@Override
public String toString() {
return "same-key";
}
}
@Nested
@DisplayName("Class and Proxy Types")
class ClassAndProxyTests {