使用Jackson进行Json动态反序列化

10

我已经看过问题 "Jackson dynamic property names",但它并没有真正回答我的问题。

我想要反序列化像这样的东西:

public class Response<T> {
    private String status;
    private Error error;
    private T data;
}

但是数据可能有不同的名称,因为存在不同的服务并返回相同的结构与一些不同的数据。例如,“用户”和“合同”:

{
  response: {
    status: "success",
    user: {
        ...
    }
  }
}

or

{
  response: {
    status: "failure",
    error : {
        code : 212, 
        message : "Unable to retrieve contract"
    }
    contract: {
        ...
    }
  }
}

我希望将我的响应对象通用化,像这样:
public class UserResponse extends Response<User> {}

我尝试了以下方法,但不确定它是否适用于我的情况或者我是否使用正确:

 @JsonTypeInfo(include = As.WRAPPER_OBJECT, use = Id.CLASS)
 @JsonSubTypes({@Type(value = User.class, name = "user"),
                    @Type(value = Contract.class, name = "contract")})

最后,我创建了一个自定义的反序列化器。它能够工作,但我不满意:

public class ResponseDeserializer extends JsonDeserializer<Response> {
@Override
public Response deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    Response responseData = new Response();
    Object data = null;

    for (; jp.getCurrentToken() != JsonToken.END_OBJECT; jp.nextToken()) {
        String propName = jp.getCurrentName();
        // Skip field name:
        jp.nextToken();

        if ("contract".equals(propName)) {
            data = mapper.readValue(jp, Contract.class);
        } else if ("user".equals(propName)) {
            data = mapper.readValue(jp, User.class);
        } else if ("status".equals(propName)) {
            responseData.setStatus(jp.getText());
        } else if ("error".equals(propName)) {
            responseData.setError(mapper.readValue(jp, com.ingdirect.dg.business.object.community.api.common.Error.class));
        }
    }

    if (data instanceof Contract) {
        Response<Contract> response = new Response<Ranking>(responseData);
        return response;
    }

    if (data instanceof User) {
        Response<User> response = new Response<User>(responseData);
        return response;
    }

    // in all other cases, the type is not yet managed, add it when needed
    throw new JsonParseException("Cannot parse this Response", jp.getCurrentLocation());
}

}

有没有使用注释的方法来实现这个功能?提前感谢!
2个回答

7

Jackson框架提供内置支持动态类型。

//Base type
@JsonTypeInfo(property = "type", use = Id.NAME)
@JsonSubTypes({ @Type(ValidResponse.class), 
                @Type(InvalidResponse.class) 
              })
public abstract class Response<T> {

} 
//Concrete type 1
public class ValidResponse extends Response<T>{

}
//Concrete type 2
public class InvalidResponse extends Response<T>{

}

main {
    ObjectMapper mapper = new ObjectMapper();
    //Now serialize
    ValidResponse response = (ValidResponse)(mapper.readValue(jsonString,      Response.class));

    //Deserialize
    String jsonString = mapper.writeValueAsString(response);
}

0

你尝试过了吗:

public class AnyResponse {
    private String status;
    private Error error;
    private Contract contract;
    private User user;
    // And all other possibilities.
}
// ...
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

这将填充JSON中出现的任何对象,并将其余部分设置为null。

然后,您可以使用相关对象填充响应。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接