为每个响应改进反序列化器

时间:2015-05-03 20:18:18

标签: java android jackson

我必须调用一个webservices,它为我查询的每个对象(用户,客户,提供者......)返回如下所示的响应

{"result":
   {"code":"OK",
    "message": {"id":"1",
                "name":"YingYang",
                "mail":"somemail@gmail.com",
                "password":"EDB5FG12BG117KMNJSYHH",
                "validated":"1",
                "status":"Just fine",
                "ranking":"99"}
   }
}

问题是,当'code'正常时,我需要获取对象“user”(或客户或其他),当'code'为KO时,我需要输入字符串消息/错误。

我知道这个结构对于webservices来说很常见,但我找不到处理它们的方法。

我想我必须创建一个自定义反序列化器来完成这项工作,这是我到目前为止所做的:

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;
    }
}

当“代码”为“KO”时,有人可以帮助我对所有对象的所有Api响应进行通用,并生成某种消息/错误吗?

1 个答案:

答案 0 :(得分:1)

基本上,你需要的是这样的东西:

@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使用接口,抽象类也可以使用。我们的想法是,所有消息(包括错误)都实现/扩展了一个通用类型。注释告诉Jackson如何基于code属性对JSON进行反序列化。

现在,为了实现这一点,您必须告诉Jackson有关消息的类型。您可以通过code参数(如上面的代码)执行此操作,并使您的JSON看起来像这样:

{"result":
   {"code":"USER",
    "message": {"<your user>"}
   }
}
// another example
{"result":
   {"code":"PROVIDER",
    "message": {"<your provider>"}
   }
}

或者,您可以在反序列化JSON时指定类型(类)。

和往常一样,尝试让你的领域成为最终/永恒。使用Jackson的一种简单方法是通过构造函数,在构造函数中注释您的参数并使用@JsonCreator标记它。如果您使用的是Java 8,那么this将非常有用。