How to stop Moshi from parsing a specific object attribute How to stop Moshi from parsing a specific object attribute json json

How to stop Moshi from parsing a specific object attribute


When Moshi looks at the hierarchy of Response class, it decides to use a JsonAdapter<String> to parse the field data. So the solution is to tell Moshi not to use JsonAdapter<String> to parse it but delegate the task to our JsonAdapter.

Talk is cheap, here is the code.

class KeepAsJsonString {  public void run() throws Exception {    String json = "" +      "{\n" +      "\"date\": \"23-03-2019\",\n" +      "\"changed\": true,\n" +      "\"data\": {\n" +      "    \"login\": \"9999999\",\n" +      "    \"loginFormatted\": \"999 99 99\"\n" +      "    }\n" +      "}";    Moshi moshi = new Moshi.Builder().add(new DataToStringAdapter()).build();    JsonAdapter<Response> jsonAdapter = moshi.adapter(Response.class);    Response response = jsonAdapter.fromJson(json);    System.out.println(response.data); // {"login":"9999999","loginFormatted":"999 99 99"}  }  static class Response {    @Json(name = "date")    public String date;    @Json(name = "changed")    public boolean changed;    // Ask moshi to forward the intermediate result to some function with a String annotated with @DataString,    // in our case, DataToStringAdapter.fromJson() and DataToStringAdapter.toJson()    @Json(name = "data")    public @DataString String data;  }  @Retention(RUNTIME)  @JsonQualifier  public @interface DataString {  }  static class DataToStringAdapter {    @ToJson    void toJson(JsonWriter writer, @DataString String string) throws IOException {      // Write raw JSON string      writer.value(new Buffer().writeUtf8(string));    }    @FromJson @DataString    String fromJson(JsonReader reader, JsonAdapter<Object> delegate) throws IOException {      // Now the intermediate data object (a Map) comes here      Object data = reader.readJsonValue();      // Just delegate to JsonAdapter<Object>, so we got a JSON string of the object      return delegate.toJson(data);    }  }  public static void main(String[] args) throws Exception {    new KeepAsJsonString().run();  }}

In Kotlin it can look like this:

@JsonQualifier@Retention(AnnotationRetention.RUNTIME)@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION)annotation class DataStringinternal class JsonObjectToStringJsonAdapter {    @ToJson    fun toJson(@DataString s: String): String {        return s    }    @FromJson    @DataString    fun fromJson(reader: JsonReader, adapter: JsonAdapter<Any>): String {        val jsonObject: Any = reader.readJsonValue()!!        return adapter.toJson(jsonObject)    }}

Update:

As Eric Cochran mentioned, there will be a more efficient way (JsonReader.readJsonString()) to read JSON as string when this issue is fixed.