简体   繁体   中英

Gson parsing into Object that contains a JsonArray

See solution at the end.

original question

I have the following object in my code that I'm trying to deserialize with Gson.

public class Foo {
    public Map<String, JSONArray> bar = new HashMap<>();
    public ... other stuff
}

I've also tried with:

public class Foo {
    public Map<String, String> bar = new HashMap<>();
    public ... other stuff
}

The reason here is because the Map will be feed into sub-modules that could be any data type. Internally each module knows how to parse its own data.

on the JsonArray version I get this error:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 
   Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 3 column 18 path $.trigger.

and in the String version I get this error:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
   Expected a string but was BEGIN_ARRAY at line 3 column 18 path $.trigger.

My question is:

Can I parse this without the need of a custom deserializer? How?

Edit: below is the relevant bits of code:

// Gson is singleton provided by Dagger2
Gson gson = new GsonBuilder().create();

// retrofit is also singleton provided by dagger
Retrofit restAdapter = new Retrofit.Builder()
    .baseUrl(baseUrl)
    .client(buildOkHttpClient(context))
    .addConverterFactory(ScalarsConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();
return restAdapter.create(ApiService.class);

// then the Retrofit API
@GET("our path")
Observable<Foo> getFoo(a couple of values);

I've also tried using a MockTransport that is directly invoking Gson, like following:

Observable
   .just(fooResponse)
   .delay(101, TimeUnit.MILLISECONDS)
   .map(new Function<String, Foo>() {
      @Override public Interactions apply(String s) throws Exception {
           return gson.fromJson(s, Foo.class);
       }
    });

and below relevant parts of the JSON:

{
  "bar": {
    "type0": [
      {
        ... object 0
      }
    ],
    "type1": [
      {
        ... object 0
      },
      {
        ... object 1
      }
    ]
  },
  "otherStuff" : {
  }
}

The json is for sure formatted correctly, it's coming from our servers and I've re-checked on jsonlint.com

solution:

it seems that is not possible to do without custom deserializer. So I wrote a serialiser for String, which sounds bad, but I' gladly accept suggestions of a better way of handling it.

.registerTypeAdapter(String.class, new JsonDeserializer<String>() {
   @Override
   public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonPrimitive()) {
            return json.getAsJsonPrimitive().getAsString();
        } else {
            return json.toString();
        }
    }
})

You got this error because you are trying to parse JsonArray but you should parse JsonObject at above mentioned line. I hope it will help!! :)

When I tried this it was working fine for me,

public class Foo {

    Map<String, List<Map>> bar = new HashMap<String, List<Map>>() ;

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM