java - Jackson JsonUnwrapped 和通用

标签 java generics jackson

我有两门课:

public class ResponseInfo {

    private final int code;

    private final String description;

    @JsonCreator
    public static ResponseInfo of(
            @JsonProperty("code") int code,
            @JsonProperty("description") String description
    ) {
        return new ResponseInfo(code, description);
    }

    private ResponseInfo(
            int code,
            String description
    ) {
        this.code = code;
        this.description = description;
    }

    @JsonProperty("code")
    public int code() {
        return code;
    }

    @JsonProperty("description")
    public String description() {
        return description;
    }
}

和:

 public class Response<T> {

    private final ResponseInfo responseInfo;

    private final T payload;

    public static <T> Response<T> of(ResponseInfo responseInfo, T payload) {
        return new Response<>(responseInfo, payload);
    }

    private Response(ResponseInfo responseInfo, T payload) {
        this.responseInfo = responseInfo;
        this.payload = payload;
    }

    @JsonUnwrapped
    public ResponseInfo responseInfo() {
        return responseInfo;
    }

    @JsonUnwrapped
    public T payload() {
        return payload;
    }
}

我使用它们将附加信息添加到响应中(作为代码和描述)。例如:

Response.of(ResponseInfo.of(0, "OK"), User.of("Oleg", 23))

将被序列化为:

{ “年龄”:23, “代码”:0, “描述”:“好的”, “姓名”:“奥列格” }

Response的反序列化是如何完成的?

我无法直接在@JsonCreator中使用@JsonProperty,因为我不知道有效负载的属性。 JsonCreator@JsonUnwrapped 也不起作用。

我正在使用jackson-datatype-jdk8:2.9.5

最佳答案

我已经创建了实现。

public class ResponseDeserializer
        extends JsonDeserializer<Response<?>>
        implements ContextualDeserializer {

    private JavaType type;

    @SuppressWarnings("unused")
    public ResponseDeserializer() {
    }

    private ResponseDeserializer(JavaType type) {
        this.type = type;
    }

    @Override
    public JsonDeserializer<?> createContextual(
            DeserializationContext context,
            BeanProperty beanProperty
    ) {
        JavaType contextualType = context.getContextualType();

        if(contextualType == null) {
            contextualType = beanProperty.getMember()
                    .getType();
        }

        if (!contextualType.isTypeOrSubTypeOf(Response.class)) {
            throw new IllegalArgumentException("contextualType should be " + Response.class.getName());
        }

        final JavaType payloadType = contextualType.containedType(0);

        return new ResponseDeserializer(payloadType);
    }

    @Override
    public Response<?> deserialize(
            JsonParser jsonParser,
            DeserializationContext context
    ) throws IOException {
        final ObjectCodec codec = jsonParser.getCodec();
        JsonNode rootNode = codec.readTree(jsonParser);

        final ResponseInfo responseInfo = ResponseInfo.of(
                rootNode.get("code").asInt(),
                rootNode.get("description").asText()
        );

        final JsonNode payloadNode = createPayloadNode(rootNode, codec);
        final JsonParser payloadParser = payloadNode.traverse();

        final Object payload = codec.readValue(payloadParser, type);
        return Response.of(responseInfo, payload);
    }

    private JsonNode createPayloadNode(JsonNode rootNode, ObjectCodec codec) {
        final Map<String, JsonNode> remainingNodes = findRemainingNodes(rootNode);

        if(remainingNodes.size() == 1) {
            final JsonNode payloadNode = remainingNodes.get("payload");

            if(payloadNode != null && !payloadNode.isObject()) {
                return payloadNode;
            }
        }

        return buildRemainingNode(remainingNodes, codec);
    }

    private JsonNode buildRemainingNode(Map<String, JsonNode> remainingNodes, ObjectCodec codec) {
        final ObjectNode remainingNode = (ObjectNode) codec.createObjectNode();
        remainingNodes.forEach(remainingNode::set);
        return remainingNode;
    }

    private Map<String, JsonNode> findRemainingNodes(JsonNode rootNode) {
        Map<String, JsonNode> remainingNodes = new HashMap<>();

        rootNode.fields()
                .forEachRemaining(entry -> {
                    final String key = entry.getKey();

                    if(key.equals("code") || key.equals("description")) {
                        return;
                    }

                    remainingNodes.put(key, entry.getValue());
                });

        return remainingNodes;
    }
}

关于java - Jackson JsonUnwrapped 和通用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50873921/

相关文章:

javascript - 使用 JSDoc 注释通用 ES6 类

java - @Nullable 与泛型 (Eclipse)

json - 使用 Jackson 进行序列化时如何仅包含特定属性

java - While 循环 While 字符串不等于多个其他字符串 (Java)

java - 自动解决jar依赖关系

Java:Method.invoke(this,args)NullPointerException

java - 使用具有通用列表属性的通用类进行反序列化

java - Jacoco report-aggregate - 包括聚合项目的报告

Swift Generic func gen<T>(arg : T) where T : Optional<U>, U : Equatable

java - 使用 jackson jersey 将复杂的 hashmap 转换为 JSON