Reputation: 39836
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();
}
}
})
Upvotes: 0
Views: 215
Reputation: 3885
When I tried this it was working fine for me,
public class Foo {
Map<String, List<Map>> bar = new HashMap<String, List<Map>>() ;
}
Upvotes: 0
Reputation: 370
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!! :)
Upvotes: 1