Jackson 将属性名称未知的 json 字符串反序列化为泛型类型

问题描述 投票:0回答:1

我想反序列化一个可以具有“未知”属性(但在编译时已知泛型)的 json 字符串,并将该未知属性反序列化为提供的泛型类型。

JSON 字符串的结构如下所示:

{
  "id":"abc",
  "human": {"name": "me", age: 99}
}
OR:
{
  "id":"abc",
  "cat": {"color": "orange"}
}
OR:
{
  "id":"abc",
  "bike": {"specs": {"speed":30}}
}

我有以下模型类:

@Value
@Builder
@Jacksonized
public class Data<T> {
  String id;
  T other; // <- how can I map "cat", "human", or "bike" into this generic
}

@V/B/J
public class Human {
  String name;
  Integer age;
}

@V/B/J
public class Cat {
  String color;
}

@V/B/J
public class Bike {
  Specs specs;
}

@V/B/J
public class Specs {
  Integer speed;
}

JSON 字符串所需的泛型将在编译时已知,例如:

Data<Human> humanData = objectMapper.readValue(jsonHumanString, TypeReference<Data<Human>>() {});
Data<Cat> catData = objectMapper.readValue(jsonCatString, TypeReference<Data<Cat>>() {});
Data<Bike> bikeData = objectMapper.readValue(jsonBikeString, TypeReference<Data<Bike>>() {});

但是,我仍然收到错误:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "human"
。如何将“自行车”、“猫”、“人”强行映射为“其他”?

java generics jackson lombok
1个回答
0
投票

我想我解决了自己的答案。我可以在整个

Data
类上使用自定义反序列化器来解析泛型。

@Value
@Builder
@JsonDeserialize(using = GenericDeserializer.class)
public class Data<T> {
    String id;
    T other;
}

解串器:

public class GenericDeserializer extends StdDeserializer<Data<?>> {

    public GenericDeserializer() {
        this(null);
    }


    public GenericDeserializer(Class<Data<?>> vc) {
        super(vc);
    }

    @Override
    public Data<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException, JsonProcessingException {
        ObjectCodec codec = jsonParser.getCodec();
        JsonNode node = codec.readTree(jsonParser);
        if (node.has("bike")) {
            return Data.<Bike>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("bike"), Bike.class))
                    .build();
        } else if (node.has("human)) {
            return Data.<Human>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("human"), Human.class))
                    .build();
        } else if (node.has("cat)) {
            return Data.<Cat>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("cat"), Cat.class))
                    .build();
        }

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.