为每个响应改造解串器
Retrofit deserializer for every response
我必须调用一个 Web 服务,它 return 对我查询的每个对象(用户、客户、提供者....)的响应如下所示
{"result":
{"code":"OK",
"message": {"id":"1",
"name":"YingYang",
"mail":"somemail@gmail.com",
"password":"EDB5FG12BG117KMNJSYHH",
"validated":"1",
"status":"Just fine",
"ranking":"99"}
}
}
问题是当 'code' OK 时我需要获取对象 "user"(或客户或其他),当 'code' 时我需要获取字符串 message/error KO.
我知道这种结构对于网络服务来说很常见,但我就是找不到处理它们的方法。
我想我必须创建一个自定义反序列化器来完成这项工作,这就是我目前所做的:
class UserDeserializer extends JsonDeserializer<User>
{
@Override
public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
{
User user = new User();
JsonNode node = jp.getCodec().readTree(jp);
ApiResult result = new ApiResult();
result.code = (String) node.get("result").get("code").toString();
result.message = (String) node.get("result").get("message").toString();
ObjectMapper mapper = new ObjectMapper();
JsonNode messageObj = mapper.readTree(result.message);
Iterator<Map.Entry<String, JsonNode>> it = messageObj.fields();
while (it.hasNext()) {
Map.Entry e = (Map.Entry)it.next();
Field field = null;
try {
field = User.class.getField((String) e.getKey());
if(field.getType().getName().equals("java.lang.String")) {
field.set(user, e.getValue().toString().replace("\"",""));
}
if(field.getType().getName().equals("int")) {
field.set(user, Integer.parseInt(e.getValue().toString().replace("\"","")));
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
return user;
}
}
任何人都可以帮助我为所有对象的所有 Api 响应制作这个通用的,并在 "code" 为 "KO" 时生成某种 message/error 吗?
基本上,你需要的是这样的:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "code")
@JsonSubTypes({
@JsonSubTypes.Type(value = Result.Error.class, name = "KO"),
@JsonSubTypes.Type(value = User.class, name = "<your string to determine whether the message is a user or not>") })
static class Result {
String code;
Message message;
interface Message {
int id();
// other common properties...
}
static class Error implements Message {
@Override
public int id() {
return -1;
}
}
static class User implements Message {
public int id;
public String name;
// other fields...
@Override
public int id() {
return id;
}
}
}
您不需要为 Message
使用接口,抽象 class 也可以。这个想法是你所有的消息(包括错误)都是 implements/extends 一个通用类型。注释告诉 Jackson 如何基于 code
属性.
反序列化 JSON
现在,为了使其正常工作,您必须将消息的类型告诉 Jackson。您可以像上面的代码一样通过 code
参数来完成它,并让您的 JSON 看起来像这样:
{"result":
{"code":"USER",
"message": {"<your user>"}
}
}
// another example
{"result":
{"code":"PROVIDER",
"message": {"<your provider>"}
}
}
或者您可以在反序列化 JSON.
时简单地指定类型 (class)
和往常一样,尝试让您的字段 final/immutable。使用 Jackson 的一种简单方法是通过构造函数,在构造函数中注释您的参数并用 @JsonCreator
标记。如果您使用 Java 8 那么 this 将非常有用。
我必须调用一个 Web 服务,它 return 对我查询的每个对象(用户、客户、提供者....)的响应如下所示
{"result":
{"code":"OK",
"message": {"id":"1",
"name":"YingYang",
"mail":"somemail@gmail.com",
"password":"EDB5FG12BG117KMNJSYHH",
"validated":"1",
"status":"Just fine",
"ranking":"99"}
}
}
问题是当 'code' OK 时我需要获取对象 "user"(或客户或其他),当 'code' 时我需要获取字符串 message/error KO.
我知道这种结构对于网络服务来说很常见,但我就是找不到处理它们的方法。
我想我必须创建一个自定义反序列化器来完成这项工作,这就是我目前所做的:
class UserDeserializer extends JsonDeserializer<User>
{
@Override
public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
{
User user = new User();
JsonNode node = jp.getCodec().readTree(jp);
ApiResult result = new ApiResult();
result.code = (String) node.get("result").get("code").toString();
result.message = (String) node.get("result").get("message").toString();
ObjectMapper mapper = new ObjectMapper();
JsonNode messageObj = mapper.readTree(result.message);
Iterator<Map.Entry<String, JsonNode>> it = messageObj.fields();
while (it.hasNext()) {
Map.Entry e = (Map.Entry)it.next();
Field field = null;
try {
field = User.class.getField((String) e.getKey());
if(field.getType().getName().equals("java.lang.String")) {
field.set(user, e.getValue().toString().replace("\"",""));
}
if(field.getType().getName().equals("int")) {
field.set(user, Integer.parseInt(e.getValue().toString().replace("\"","")));
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
return user;
}
}
任何人都可以帮助我为所有对象的所有 Api 响应制作这个通用的,并在 "code" 为 "KO" 时生成某种 message/error 吗?
基本上,你需要的是这样的:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "code")
@JsonSubTypes({
@JsonSubTypes.Type(value = Result.Error.class, name = "KO"),
@JsonSubTypes.Type(value = User.class, name = "<your string to determine whether the message is a user or not>") })
static class Result {
String code;
Message message;
interface Message {
int id();
// other common properties...
}
static class Error implements Message {
@Override
public int id() {
return -1;
}
}
static class User implements Message {
public int id;
public String name;
// other fields...
@Override
public int id() {
return id;
}
}
}
您不需要为 Message
使用接口,抽象 class 也可以。这个想法是你所有的消息(包括错误)都是 implements/extends 一个通用类型。注释告诉 Jackson 如何基于 code
属性.
现在,为了使其正常工作,您必须将消息的类型告诉 Jackson。您可以像上面的代码一样通过 code
参数来完成它,并让您的 JSON 看起来像这样:
{"result":
{"code":"USER",
"message": {"<your user>"}
}
}
// another example
{"result":
{"code":"PROVIDER",
"message": {"<your provider>"}
}
}
或者您可以在反序列化 JSON.
时简单地指定类型 (class)和往常一样,尝试让您的字段 final/immutable。使用 Jackson 的一种简单方法是通过构造函数,在构造函数中注释您的参数并用 @JsonCreator
标记。如果您使用 Java 8 那么 this 将非常有用。