GSON: knowing what type of object to convert to?
I'm looking into using Google's GSON for my Android project that will request JSON from my web server. The JSON returned will be either...
1) A successful response of a known type (e.g.: class "User"):
{
"id":1,
"username":"bob",
"created_at":"2011-01-31 22:46:01",
"PhoneNumbers":[
{
"type":"home",
"number":"+1-234-567-8910"
},
{
"type":"mobile",
"number":"+1-098-765-4321"
}
]
}
2.) An unsuccessful response, which will always take on the same basic structure below.
{
"error":{
"type":"Error",
"code":404开发者_运维问答,
"message":"Not Found"
}
}
I'd like GSON to convert to the correct type depending on the existence of the error
key/value pair above. The most practical way I can think to do this is as follows, but I'm curious if there's a better way.
final String response = client.get("http://www.example.com/user.json?id=1");
final Gson gson = new Gson();
try {
final UserEntity user = gson.fromJson(response, UserEntity.class);
// do something with user
} catch (final JsonSyntaxException e) {
try {
final ErrorEntity error = gson.fromJson(response, ErrorEntity.class);
// do something with error
} catch (final JsonSyntaxException e) {
// handle situation where response cannot be parsed
}
}
This is really just pseudocode though, because in the first catch condition, I'm not sure how to test whether the key error
exists in the JSON response. So I guess my question is twofold:
- Can I / how can I use GSON to test the existence of a key, and make a decision on how to parse based upon that?
- Is this what others in a similar situation are doing with GSON, or is there a better way?
What you'd normally want to do is to have your server return an actual error code along with the JSON error response. Then you read the response as an ErrorEntity
if you get an error code and as a UserEntity
if you get 200. Obviously this requires a little more dealing with the details of communication with the server than just turning a URL in to a String, but that's how it is.
That said, I believe another option would be to use a custom JsonDeserializer
and a class that can return either a value or an error.
public class ValueOrErrorDeserializer<V> implements JsonDeserializer<ValueOrError<V>> {
public ValueOrError<V> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) {
JsonObject object = json.getAsJsonObject();
JsonElement error = object.get("error");
if (error != null) {
ErrorEntity entity = context.deserialize(error, ErrorEntity.class);
return ValueOrError.<V>error(entity);
} else {
Type valueType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
V value = (V) context.deserialize(json, valueType);
return ValueOrError.value(value);
}
}
}
You'd then be able to do something like this:
String response = ...
ValueOrError<UserEntity> valueOrError = gson.fromJson(response,
new TypeToken<ValueOrError<UserEntity>>(){}.getType());
if (valueOrError.isError()) {
ErrorEntity error = valueOrError.getError();
...
} else {
UserEntity user = valueOrError.getValue();
...
}
I haven't tried that code out, and I'd still recommend using the HTTP error code, but it gives you an example of how you can use a JsonDeserializer
to decide what to do with some JSON.
精彩评论