google / gson

A Java serialization/deserialization library to convert Java Objects into JSON and back
Apache License 2.0
23.34k stars 4.28k forks source link

java.util.ConcurrentModificationException #2714

Open w296488320 opened 3 months ago

w296488320 commented 3 months ago

Gson version

2.11.0

Java / Android version

java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(HashMap.java:1574) at java.util.HashMap$EntryIterator.next(HashMap.java:1607) at java.util.HashMap$EntryIterator.next(HashMap.java:1605) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:220) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:154) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.write(ReflectiveTypeAdapterFactory.java:247) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:490) at com.google.gson.Gson.toJson(Gson.java:944) at com.google.gson.Gson.toJson(Gson.java:899) at com.google.gson.Gson.toJson(Gson.java:848) at com.google.gson.Gson.toJson(Gson.java:825)

Used tools

Description

Expected behavior

Actual behavior

Reproduction steps

  1. ...
  2. ...

Exception stack trace

Marcono1234 commented 3 months ago

Can you please provide a minimal, reproducible example so that we can reproduce this issue? For example maybe some other part of your code is concurrently modifying the HashMap at the same time your are serializing it with Gson.

ApoloRossi commented 2 months ago

I'm having exactly the same problem in the piece of code below:

fun trackValue(trigger: Map<String, Array>?) { val json = Gson().toJson(ConcurrentHashMap<String, Any>().apply { put("key1","X") put("key2","Y") put("key3","Z") put("trigger", trigger.toString()) }) print(json.toString()) }

Notes:

The only case that its happening this crash is within Gson().toJson().

It's difficult to reproduce this error but at my company we have millions of active users and a low percentage of them are getting this exception.

Marcono1234 commented 2 months ago

The trigger value passed as parameter is Map so it cannot be modified.

But only within this function the type is Map, the caller might have it as MutableMap and might be modifying it concurrently? Or are you calling Java code with trigger? Because Java only has the interface java.util.Map, which is mutable, so even if you pass a Kotlin (non-mutable) Map, the Java code can still modify it (unless you used java.util.Collections#unmodifiableMap or similar).

I assume whether you use ConcurrentHashMap in your code example does not matter, since that is only a temporarily map created in the trackValue function and is only visible to Gson.

Does your code snippet really match your production code? The trigger.toString() looks a bit dubious because it does not create JSON data, so you can most likely not parse it afterwards again; and also that call would be executed before toJson is called, so I don't understand how that could result in the ConcurrentModificationException for toJson in the end.