我正在使用Volley
和Gson
与Java Reflection
反序列化我的JSON
响应。我有一个特定的JSON
字段,可以返回为JSONObject
,这意味着一个对象类或JSONArray
,这意味着一个对象类的数组/列表。
我需要反映这个字段并在运行时更改其类型。
以下是我尝试解析的JSON
示例:
{
"status message": "User Return Succsessfully",
"status code": 200,
"status Custom code": 0,
"data": {
"user_id": 5,
"first_name": "Name1",
"last_name": "Name2",
"email": "me@mail.com",
}
}
这个有数组:
{
"status message": "User Return Succsessfully",
"status code": 200,
"status Custom code": 0,
"data": [
1,
2,
3
]
}
这是我的Object类:
public class BaseResponse implements Parsable, Serializable {
@SerializedName("status message")
@Expose
private String statusMessage;
@SerializedName("status code")
@Expose
private Integer statusCode;
@SerializedName("data")
@Expose
private Object object = null;
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
@Override
public Object parse(JsonElement jsonElement) {
return new Gson().fromJson(jsonElement, BaseResponse.class);
}
}
"data"
字段可能是JSONObject
(需要将其解析为SomeObjectClass
)或JSONArray
(需要将其解析为SomeObjectClass2
列表)
当我收到回复并以Gson
格式返回时,我收到LinkedTreeMap
,我无法将其解析为SomeObjectClass
或SomeObjectClass2
我需要反映"data"
字段以根据响应获取任何类型的Object类。
我使用以下类返回响应:
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Response.Listener<T> listener;
private final Type type;
/**
* Make a GET request and return a parsed object from JSON.
*
* @param url URL of the request to make
* @param clazz Relevant class object, for Gson's reflection
* @param headers Map of request headers
*/
public GsonRequest(int method, String url, Class<T> clazz, Type type, Map<String, String> headers,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.clazz = clazz;
this.type = type;
this.headers = headers;
this.listener = listener;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
如何实现我的目标?
答案 0 :(得分:1)
你获得LinkedTreeMap
个实例的原因是Gson没有足够的数据类型信息。您的BaseResponse
只提供Object
Gson没有类型信息提示,因此您必须在反序列化之前向Gson提供此类型信息。您可以拥有与此类似的BaseResponse
类:
// Type parameterization <T> is used for conveniences at the use-site only
// Gson can't work with it without a type information hint anyway
// The Parsable interface seems to be unnecessary here -- parsing is a scope for Gson
final class BaseResponse<T>
implements Serializable {
@SerializedName("status message")
@Expose
final String statusMessage = null;
@SerializedName("status code")
@Expose
final Integer statusCode = null;
@SerializedName("data")
@Expose
final T data = null;
}
请注意,上面的类只代表一个响应,一个简单的数据映射,没有别的。如果你提供Gson类型的提示,用“vanilla”Gson解析你的JSON非常简单:
private static final String JSON_1 = "{\"status message\":\"User Return Succsessfully\",\"status code\":200,\"status Custom code\":0,\"data\":{\"user_id\":5,\"first_name\":\"Name1\",\"last_name\":\"Name2\",\"email\":\"me@mail.com\"}}";
private static final String JSON_2 = "{\"status message\":\"User Return Succsessfully\",\"status code\":200,\"status Custom code\":0,\"data\":[1,2,3]}";
// Java has java.lang.reflect.Type that provides more type information than a java.lang.Class does
// Why? The Class holds information about a concrete type, whilst Type can hold information about types that do not even exist in the application
// TypeToken instances declaration may look weird, but it's a nice and elegant way of specifying the type information via type parameters
private static final Type userBaseResponseType = new TypeToken<BaseResponse<User>>() {
}.getType();
private static final Type listOfIntegersBaseResponseType = new TypeToken<BaseResponse<List<Integer>>>() {
}.getType();
// Gson instances are known to be thread-safe so can be instantiated once and shared
// Instantiating a Gson instance is relatively an expensive operation, and just cache it
private static final Gson gson = new Gson();
public static void main(final String... args) {
// Now just pass a Type instance to Gson
// Note that the `fromJson(..., Type)` can "cast" itself, and passing just BaseResponse.class would work the same (not enough type information + unchecked warnings)
final BaseResponse<User> userResponse = gson.fromJson(JSON_1, userBaseResponseType);
final BaseResponse<List<Integer>> listOfIntegersResponse = gson.fromJson(JSON_2, listOfIntegersBaseResponseType);
final User user = userResponse.data;
System.out.println(user.firstName + " " + user.lastName + " (" + user.email + ")");
System.out.println(listOfIntegersResponse.data);
}
User
类的位置如下:
final class User {
@SerializedName("user_id")
@Expose
final Integer userId = null;
@SerializedName("first_name")
@Expose
final String firstName = null;
@SerializedName("last_name")
@Expose
final String lastName = null;
@SerializedName("email")
@Expose
final String email = null;
}
输出:
Name1 Name2(me@mail.com)
[1,2,3]
现在,您可以从Class<T> clazz
中移除GsonRequest
,以便通过java.lang.reflect.Type
正确提供类型信息(您的Type type
代表什么?)或Gson TypeToken<T>
方法调用的fromJson
。
旁注。您可以避免隐式克隆您传递给String构造函数的response.data
数组。至于我看到Volley如何工作,你可以像这样包装它的data
字段:
final Reader reader = new StringReader(new ByteArrayInputStream(response.data), HttpHeaderParser.parseCharset(response.headers));
... = gson.fromJson(reader, type), ...
这样可以为大回复节省一些内存。
答案 1 :(得分:0)
这样的事情:
public class BaseResponse<T> implements Parsable, Serializable {
@SerializedName("status message")
@Expose
private String statusMessage;
@SerializedName("status code")
@Expose
private Integer statusCode;
@SerializedName("data")
@Expose
private T object = null;
private Class<T> type;
public BaseResponse(Class<T> zz) {
type = zz;
}
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public T getObject() {
return object;
}
public void setObject(T object) {
this.object = object;
}
@Override
public T parse(JsonElement jsonElement) {
return new Gson().fromJson(jsonElement, type);
}
}
或者查看一下:http://www.artima.com/weblogs/viewpost.jsp?thread=208860
示例:
GsonRequest(method, url, SomeObjectClass.class, type, headers, listener, errorListener)
SomeObjectClass:
public class SomeObjectClass {
public long user_id;
public String first_name;
public String last_name;
public String email;
}