3

I want to serialize an Object to Map by Moshi.Here is my codes by Gson

    public static Map<String, String> toMap(Object obj, Gson gson) {
    if (gson == null) {
        gson = new Gson();
    }
    String json = gson.toJson(obj);
    Map<String, String> map = gson.fromJson(json, new TypeToken<Map<String, String>>() {
    }.getType());
    return map;
}

And how to write by Moshi ?

Nano Java8
  • 41
  • 1
  • 1
  • 3
  • See https://stackoverflow.com/questions/47114344/moshi-in-android-kotlin-enum-as-mutablemap-key-being-converted-to-string-when/47114650#47114650 – Erlang Parasu Jun 30 '20 at 21:24

5 Answers5

11

Here's one way. Check out the toJsonValue doc here.

Moshi moshi = new Moshi.Builder().build();

JsonAdapter<Object> adapter = moshi.adapter(Object.class);

Object jsonStructure = adapter.toJsonValue(obj);
Map<String, Object> jsonObject = (Map<String, Object>) jsonStructure;

If you know the type of obj, it'd be better to look up the adapter of that type, rather than of Object. (The Object JsonAdadpter has to look up the runtime type on every toJson call.

Eric Cochran
  • 8,414
  • 5
  • 50
  • 91
7

@NanoJava8 solution crashes but can be made to work with a minor change using Map instead of HashMap

Type type = Types.newParameterizedType(Map.class, String.class, String.class);

JsonAdapter<Map<String,String>> adapter = moshi.adapter(type);

Map<String,String> map = adapter.fromJson(json);

As stated by Jesse in the answer Moshi support fields as Map but not HashMap.

farhan patel
  • 1,490
  • 2
  • 19
  • 30
3

In Kotlin:

val type = Types.newParameterizedType(
            MutableMap::class.java,
            String::class.java,
            String::class.java
        )
        val adapter: JsonAdapter<Map<String, String>> = moshi.adapter(type)
        val map: Map<String, String> = adapter.fromJson(responseJson)
Sasha Balyas
  • 420
  • 5
  • 13
1
Type type = Types.newParameterizedType(HashMap.class, String.class, String.class);

JsonAdapter<Map<String,String>> adapter = moshi.adapter(type);

Map<String,String> map = adapter.fromJson(json);
Nano Java8
  • 41
  • 1
  • 1
  • 3
1
class HashMapJsonAdapter<K, V>(
  private val keyAdapter: JsonAdapter<K>,
  private val valueAdapter: JsonAdapter<V>
) : JsonAdapter<HashMap<K, V>>() {

  @Throws(IOException::class)
  override fun toJson(writer: JsonWriter, map: HashMap<K, V>?) {
    writer.beginObject()
    for ((key, value) in map ?: emptyMap<K, V>()) {
      if (key == null) {
        throw JsonDataException("Map key is null at ${writer.path}")
      }
    keyAdapter.toJson(writer, key)
    valueAdapter.toJson(writer, value)
    }
    writer.endObject()
  }

  @Throws(IOException::class)
  override fun fromJson(reader: JsonReader): HashMap<K, V>? {
    val result = linkedMapOf<K, V>()
    reader.beginObject()
    while (reader.hasNext()) {
      val name = keyAdapter.fromJson(reader)
      val value = valueAdapter.fromJson(reader)
      val replaced = result.put(name!!, value!!)
      if (replaced != null) {
        throw JsonDataException("Map key '$name' has multiple values at path ${reader.path} : $replaced and value")
      }
    }
    reader.endObject()
    return result
  }

  override fun toString(): String = "JsonAdapter($keyAdapter=$valueAdapter)"

  companion object
}
Kristy Welsh
  • 7,828
  • 12
  • 64
  • 106
  • Any idea how to fix: Caused by: java.lang.IllegalArgumentException: Expected at least one `@ToJson` or `@FromJson` method on ...HashMapJsonAdapter – GuilhE May 19 '20 at 17:01