google / google/gson

Deserialized Map's values() cannot be serialized again

Open
#1,394 4 comments 1 reaction 0 assignees View on GitHub
bug
Dominant language
Java
Stars
24.2k
Forks
4.5k
Avg merge
6d 4h
Merged PRs (30d)
12

Description

Consider this test: it should pass the same way it passes for other built-in collections:
(please excuse my Kotlin, if needed I will transform to Java)
```kotlin
class VirtualCollectionSerializationTest {
class Data(val map: Map) // Kotlin nested classes are static by default.

@Test
fun testValues() {
val gson = Gson()

val deserialized = gson.fromJson("""{"map":{"key":"value"}}""", Data::class.java)
assertNotNull(deserialized)

assertEquals("""["value"]""", gson.toJson(HashMap(deserialized.map).values))
assertEquals("""["value"]""", gson.toJson(LinkedHashMap(deserialized.map).values))
assertEquals("""["value"]""", gson.toJson(TreeMap(deserialized.map).values))
assertEquals("""["value"]""", gson.toJson(ArrayList(deserialized.map.values)))
assertEquals("""["value"]""", gson.toJson(LinkedList(deserialized.map.values)))
assertEquals("""["value"]""", gson.toJson(HashSet(deserialized.map.values)))
assertEquals("""["value"]""", gson.toJson(TreeSet(deserialized.map.values)))
// Failure org.junit.ComparisonFailure: Expected: ["value"] Actual: null
assertEquals("""["value"]""", gson.toJson(deserialized.map.values))
}

@Test
fun testKeys() {
val gson = Gson()

val deserialized = gson.fromJson("""{"map":{"key":"value"}}""", Data::class.java)
assertNotNull(deserialized)

assertEquals("""["key"]""", gson.toJson(HashMap(deserialized.map).keys))
assertEquals("""["key"]""", gson.toJson(LinkedHashMap(deserialized.map).keys))
assertEquals("""["key"]""", gson.toJson(TreeMap(deserialized.map).keys))
assertEquals("""["key"]""", gson.toJson(ArrayList(deserialized.map.keys)))
assertEquals("""["key"]""", gson.toJson(LinkedList(deserialized.map.keys)))
assertEquals("""["key"]""", gson.toJson(HashSet(deserialized.map.keys)))
assertEquals("""["key"]""", gson.toJson(TreeSet(deserialized.map.keys)))
assertEquals("""["key"]""", gson.toJson(deserialized.map.keys))
}

// this test is just for checking, the important is keys and values
@Test
fun testEntries() {
val gson = GsonBuilder()
.registerTypeAdapter(Map.Entry::class.java, JsonSerializer> { src, _, _ ->
JsonObject().apply { addProperty(src.key, src.value) }
})
.create()

val deserialized = gson.fromJson("""{"map":{"key":"value"}}""", Data::class.java)
assertNotNull(deserialized)

assertEquals("""[{"key":"value"}]""", gson.toJson(HashMap(deserialized.map).entries))
assertEquals("""[{"key":"value"}]""", gson.toJson(LinkedHashMap(deserialized.map).entries))
assertEquals("""[{"key":"value"}]""", gson.toJson(TreeMap(deserialized.map).entries))
// next three are StackOverflowError, didn't check why
//assertEquals("""[{"key":"value"}]""", gson.toJson(ArrayList(deserialized.map.entries)))
//assertEquals("""[{"key":"value"}]""", gson.toJson(LinkedList(deserialized.map.entries)))
//assertEquals("""[{"key":"value"}]""", gson.toJson(HashSet(deserialized.map.entries)))
// java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap$Node cannot be cast to java.lang.Comparable; this is not a Gson issue
//assertEquals("""[{"key":"value"}]""", gson.toJson(TreeSet(deserialized.map.entries)))
assertEquals("""[{"key":"value"}]""", gson.toJson(deserialized.map.entries))
}
}
```
So the only one not working I found so far was the built-in Gson `LinkedTreeMap` implementation. Because it doesn't have an override for the `values()` method and the default implementation in `AbstractMap` is an anonymous inner class which is excluded from serialization. `keySet()` and `entries()` is supported with a simple inner class.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.