TypeAdapters don't apply to map keys
See original GitHub issueWhen converting a Map to Json, TypeAdapters
are not being used to generate the keys. Here is a minimal repro:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
class Main {
/** An example class that just wraps a String. */
static class Thinger {
public final String key;
Thinger(String key) {
this.key = key;
}
@Override
public String toString() {
return "Thinger(" + key + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Thinger that = (Thinger) o;
return Objects.equals(key, that.key);
}
@Override
public int hashCode() {
return Objects.hash(key);
}
}
/** A TypeAdapter that can encode and decode a Thinger */
static class ThingerAdapter extends TypeAdapter<Thinger> {
@Override
public void write(JsonWriter out, Thinger value) throws IOException {
out.value(value.key);
}
@Override
public Thinger read(JsonReader in) throws IOException {
return new Thinger(in.nextString());
}
}
public static void main(String[] args) {
// Sample data with custom keys and values
final Map<Thinger, Thinger> map = new HashMap<>();
map.put(new Thinger("Foo"), new Thinger("Bar"));
map.put(new Thinger("Baz"), new Thinger( "Qux"));
// Register the adapter we defined above
final Gson gson = new GsonBuilder().registerTypeAdapter(Thinger.class, new ThingerAdapter()).create();
// Print the encoded JSON
System.out.println(gson.toJson(map));
}
}
I expect this to print:
{"Foo":"Bar","Baz":"Qux"}
But it actually calls the toString
method and prints:
{"Thinger(Foo)":"Bar","Thinger(Baz)":"Qux"}
I’m not familiar with your code base, but it looks like the problem is related to this line of code
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (2 by maintainers)
Top Results From Across the Web
How to customize MapTypeAdapterFactory - Google Groups
But I stuck on only trying to make Gson to work with a custom ... private final class Adapter<K, V> extends TypeAdapter<Map<K, V>>...
Read more >Gson ignores custom Serializer for Key in a Map
The easiest way I've found seems to be to to set the enableComplexMapKeySerialization() option when initially building your Gson object.
Read more >Marshalling field of type Map[String, List[ComplexTypeWsDTO ...
The field "mapFieldName" in my Data object needs to have a different name in my WsDTO object it is mapped to. Otherwise the...
Read more >Maps API Key | Create a Map App | Bing Maps for Enterprise
Head to the Bing Maps Dev Center and click “Sign In” to use your existing Microsoft Account to generate an API key. Don't...
Read more >Gson — Mapping of Arrays and Lists of Objects - Future Studio
does the problem have anything to do with the fact that my individual data points are not key:value pairs, and are instead a...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks for your help with this! I’m going to go ahead and resolve this issue. Seems like, at a philosophical level, it’s believed this should be the responsibility of the library consumers and not the library itself.
Cheers!
You could just implement your custom map type adapter factory that might do the job for you or provide a transformed
Map<String, ...>
before its gets to thetoJson
method. The reason why the default map type adapter deals with strings only is that JSON object keys must be strings, that also keeps the type adapter API more simple requiring no provided context or adding special methods, whereas type adapters are designed for JSON values of arbitratry structure only. I’m afraid it’s not a good idea to add a new JSON objects-only method to type adapters (I can see at least two pitfalls: sacrificing the type adapter class design for JSON objects; potentially complex reuse because of inheritance). By the way, type JsonReader and JsonWriter usenextName()
andname()
for JSON object keys, notnextString()
/value(String)
.It does not produce/consume a JSON object: it represents a map using a two-dimensional JSON array (with n x 2 elements, literally
[[k1, v1], [k2, v2], ...]
), since arrays can hold arbitrary JSON elements, including null values. This is wherekeyToString
comes into play.I do believe that if you find that the
Map
-dedicated type adapter does not work for you, you might reimplement it not diving deep into the core design.