java - 使用objectmapper解析多态对象

标签 java jackson objectmapper strava

我正在尝试使用 jackson 对象映射器解析多态对象(它来自 Strava api)。该对象看起来像这样:

[
  {
    "type": "latlng",
    "data": [
      [ 38.603734, -122.864112 ],
      [ 38.608798, -122.867714 ],

      ... omitted for brevity ...

      [ 38.611205, -122.870848 ],
      [ 38.603579, -122.863891 ]
    ],
    "series_type": "distance",
    "original_size": 512,
    "resolution": "low"
  },
  {
    "type": "distance",
    "data": [
      0.0,
      1305.8,

      ... omitted for brevity ...

      128136.6,
      129444.1
    ],
    "series_type": "distance",
    "original_size": 512,
    "resolution": "low"
  }
]

因此,根据字段数据的类型,其中有不同的对象。在大多数情况下,它是一个 float 组。在“latlng”的情况下,有一个 float[] 数组,因此它是一个 float[][] (我认为)。 我使用反序列化器创建一个表示此数据结构的对象。它看起来像这样:

public class StravaStream {


    @JsonProperty("type")
    private String type;

    public String getType() {
        return type;
    }


    public static class StravaStream1D extends StravaStream {
        @JsonProperty("data")
        private float[] data;

        public StravaStream1D() {
        }

        public float[] getData() {
            return data;
        }


    }

    public static class StravaStream2D extends StravaStream {

        @JsonProperty("data")
        private float[][] data;

        public StravaStream2D() {
        }

        public float[][] getData() {
            return data;
        }

    }

    public StravaStream() {
    }


    public static class StravaStreamDeserializer extends StdDeserializer<StravaStream> {
        public StravaStreamDeserializer() {
            super(StravaStream.class);
        }

        @Override
        public StravaStream deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            Class<? extends StravaStream> variantStravaStream;
            ObjectMapper mapper = (ObjectMapper) jp.getCodec();
            ObjectNode root = (ObjectNode) mapper.readTree(jp);
            JsonNode type = root.get("type");
            System.out.println("type is "+type);
            if (type.textValue().equals("latlng")) {
                variantStravaStream = StravaStream2D.class;
            } else {
                variantStravaStream = StravaStream1D.class;
            }
                System.out.println("variant is "+variantStravaStream.getSimpleName());

            return mapper.readValue(jp, variantStravaStream);
        }
    }
}

当我只要求一维数据(例如距离物体等)时,效果很好。但是当我尝试解析“latlng”float[][]时, jackson 失败了。我确信该类型已被识别,请参阅附加 system.out,它打印出使用了 StravaStream2D.class 变体。 我收到的错误消息(以及附加系统输出)是:

01-26 09:05:49.605 27165-27165/nl.jfvh.stravatest I/System.out: type is "latlng"
01-26 09:05:49.605 27165-27165/nl.jfvh.stravatest I/System.out: variant is StravaStream2D
01-26 09:05:49.620 27165-27165/nl.jfvh.stravatest W/System.err: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of float[] out of VALUE_NUMBER_FLOAT token
01-26 09:05:49.620 27165-27165/nl.jfvh.stravatest W/System.err:     at [Source: java.io.StringReader@e8550ec; line: 1, column: 40164] (through reference chain: java.util.ArrayList[0]->nl.jfvh.stravatest.client.model.StravaStream2D["data"]->[Ljava.lang.Object[][0])

我的数据模型是否错误?多态对象的解析对我来说是非常新的,我遵循了一些教程,但问题似乎出在 float[][] 上的数据的简单映射...

最佳答案

由于(根据您的说法)您是解析多态对象的新手,我建议使用注释而不是自定义反序列化器。很简单:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(name = "latlng", value = StravaStream.StravaStream2D.class),
        @JsonSubTypes.Type(name = "distance", value = StravaStream.StravaStream1D.class)
})
public class StravaStream {

阅读 JsonTypeInfo 的文档和 JsonSubTypes

您正在尝试使用的自定义反序列化器的一个问题是,当您执行 return mapper.readValue(jp, variantStravaStream); 时最后它实际上会重新进入解串器,因为 class StravaStream2D extends StravaStream所以 Jackson 将再次使用自定义解串器。由于无限递归,我在尝试此操作时遇到了堆栈溢出错误。

关于java - 使用objectmapper解析多态对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48457691/

相关文章:

java - 为什么在 Entry<K,V> 中需要键入参数 <K,V>?

java - 如何在 Json 树中按名称查找节点?

java - Jackson ObjectMapper readValue() 解析为对象时无法识别字段

java - 创建通用的 ObjectMapper 方法以跨多个 POJO 类进行反序列化

java - 如何保留 lambda 的参数类型?

java - 选择垃圾收集器的性能指标

java - 一个在intelliJ中运行但不在cmd中运行的java应用程序

java - 在第 3 方类上更改 json 属性 jackson 的字段

java - 使用 Jackson 反序列化包含 2 个具有相同子对象的对象的数组?

java - 将对象转换为 JSON 字符串时发生 JsonMappingException - org.apache.avro.AvroRuntimeException : Not an array: