java - 使用 Jackson 反序列化 2D Json 数组时抛出错误

标签 java arrays json multidimensional-array jackson

我正在尝试从 JSON 反序列化两件事。第一个的格式如下:

String json = "[{\"name\":\"Random\"," +
        "\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";

这是第二个:

String json2 = "[{\"name\":\"Random\"," + "\"longitude\":-3.1, \"latitude\":55}]

我的代码很简单,如下:

ObjectMapper mapper = new ObjectMapper();
var asArray = mapper.readValue(json, NoFlyZone[].class);
var asArray2 = mapper.readValue(json, LngLat.class);

NoFlyZone 类:

record NoFlyZone(LngLat[] coordinates) {

    @JsonIgnoreProperties("name")
    NoFlyZone (@JsonProperty("coordinates") double[][] coordinates) {
        this(doubleArrayToLngLatArray(coordinates));
    }
    private static LngLat[] doubleArrayToLngLatArray(double[][] coordinates) {
        var coordinateArray = new LngLat[coordinates.length];
        for (int i = 0; i < coordinates.length; i++) {
            coordinateArray[i] = new LngLat(coordinates[i][0], coordinates[i][1]);
        }
        System.out.println(coordinateArray);
        return coordinateArray;
    }

}

最后是 LngLat 类:

record LngLat(double lng, double lat) {

    LngLat (@JsonProperty("longitude") double lng,
            @JsonProperty("latitude") double lat) {
        this.lng = lng;
        this.lat = lat;
    }
}

我尝试按照上面所示的方式反序列化它们,但是在尝试反序列化第一个字符串时会抛出 MismatchedInputException ,并显示错误消息“无法从数组值( token uk.ac.ed.inf.LngLat )反序列化 JsonToken.START_ARRAY 类型的值。 ……”。我不确定为什么会发生这种情况,因此我们将不胜感激。

我也尝试过添加注释

@JsonFormat(shape = JsonFormat.Shape.ARRAY)

并按照亚历山大的答案中详细说明的方式修复它,但是第二个字符串在尝试反序列化时会抛出错误。

最佳答案

自您记录以来LngLat表示为 JSON 数组(如 "[-3.1, 55.4]" ),您需要自定义其反序列化。

为此,您可以使用 @JsonFormat 提供属性 shape 的注释值为 JsonFormat.Shape.ARRAY 。这将指示 Jackson 按照声明的顺序填充数组中的记录属性。

@JsonFormat(shape = JsonFormat.Shape.ARRAY)
record LngLat(double lng, double lat) {}

并附上记录NoFlyZone将被简化为(用于解析数组的特殊方法 LngLat 是多余的):

@JsonIgnoreProperties("name")
record NoFlyZone(LngLat[] coordinates) {}

使用示例:

String json = "[{\"name\":\"Random\"," +
    "\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";
        
ObjectMapper mapper = new ObjectMapper();

System.out.println(mapper.readValue(json, new TypeReference<List<NoFlyZone>>() {}));

输出: 注意: toString() NoFlyZone的方法已被覆盖以正确显示数组

[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.4], LngLat[lng=-3.1, lat=55.9], LngLat[lng=-3.7, lat=55.3], LngLat[lng=-3.8, lat=55.7], LngLat[lng=-3.0, lat=55.8]]}]

更新

如果需要支持两种完全不同的JSON结构,那么还需要对 NoFlyZone 进行自定义反序列化级别(因为其 JSON 形状不同)。

实现这一点的方法之一是引入用 @JsonCreator 注释的工厂方法。 。它期望有一个 Map<String, JsonNode> 类型的参数为了能够汇集所有的属性。

我们还需要设置ignoreUnknown的属性的@JsonIgnorePropertiestrue .

注意: LngLat 的定义保持不变(如上所示,用 @JsonFormat 注释)。

@JsonIgnoreProperties(ignoreUnknown = true)
public record NoFlyZone(LngLat[] coordinates) {
    
    @JsonCreator
    public static NoFlyZone getInstance(Map<String, JsonNode> fields) throws IOException {
        
        boolean isArray = fields.containsKey("coordinates");

        LngLat[] longLat;
        
        if (isArray) {
            ObjectReader reader = new ObjectMapper().readerFor(LngLat[].class);
            longLat = reader.readValue(fields.get("coordinates")); // parsing JsonNode which corresponds to "coordinates" property
        } else {
            longLat = new LngLat[] { // creating a single-element array
                new LngLat(
                    Double.parseDouble(fields.get("longitude").toString()),
                    Double.parseDouble(fields.get("latitude").toString())
                )
            };
        }
        return new NoFlyZone(longLat);
    }
    
    // toString()
}

使用示例:

String json1 = "[{\"name\":\"Random\"," +
    "\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";
    
String json2 = "[{\"name\":\"Random\"," + "\"longitude\":-3.1, \"latitude\":55}]";
        
ObjectMapper mapper = new ObjectMapper();

System.out.println(mapper.readValue(json1, new TypeReference<List<NoFlyZone>>() {}));
System.out.println(mapper.readValue(json2, new TypeReference<List<NoFlyZone>>() {}));

输出:

[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.4], LngLat[lng=-3.1, lat=55.9], LngLat[lng=-3.7, lat=55.3], LngLat[lng=-3.8, lat=55.7], LngLat[lng=-3.0, lat=55.8]]}]
[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.0]]}]

关于java - 使用 Jackson 反序列化 2D Json 数组时抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74600808/

相关文章:

c++ - 如何将指向 int(数组)的指针复制到 int 数组?

javascript - 我可以组合 API/values 和 API/values/:id in 1 route file?

javascript - 使用 D3 逐节点构建图

java - 每个参数调用的 Junit 参数化测试

java - Spring Boot Web starter View 位置

arrays - Google Sheets 查询 - 不像部分匹配

java - 在多维数组中存储信息并在JOptionPane中显示信息

json - 如何修复错误类型 'System.Web.Script.Serialization.JavaScriptSerializer' 未定义

java - 如何获取数组列表中前三个最大值的索引

java - 这个匿名内部类的替代品是什么?