简体   繁体   English

如何用 Jackson 解析嵌套数组?

[英]How to parse nested arrays with Jackson?

I used to successfully parse the following .json file:我曾经成功解析过以下 .json 文件:

[
    {
        "latitude": 49.419459253939316,
        "longitude": 8.676411621072491
    },
    {
        "latitude": 49.41946061080915,
        "longitude": 8.676411644939083
    },
    {
        "latitude": 49.420365910782735,
        "longitude": 8.676438042403413
    }
]

The following Jackson script outputs a List of points.以下Jackson 脚本输出一个点List

private static <T> List<T> parseFile(final String fileName, 
                                     Class<T> contentType) {
    // ...
    InputStream inputStream = // Open file
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        TypeFactory typeFactory = objectMapper.getTypeFactory();
        CollectionType collectionType = typeFactory
            .constructCollectionType(List.class, contentType);
        return objectMapper.readValue(inputStream, collectionType);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

Now the dataset gets more complicated.现在数据集变得更加复杂。 The List of points becomes a List of List of points.List变成点List List I structured it this way - please correct me if this is not correct.我是这样构建的 - 如果这不正确,请纠正我。

[
    [
        {
            "latitude": 49.419459253939316,
            "longitude": 8.676411621072491
        },
        {
            "latitude": 49.41946061080915,
            "longitude": 8.676411644939083
        },
        {
            "latitude": 49.420365910782735,
            "longitude": 8.676438042403413
        }
    ],
    [
        {
            "latitude": 49.40460334213399,
            "longitude": 8.670034018853409
        },
        {
            "latitude": 49.404608057285145,
            "longitude": 8.670028775634165
        },
        {
            "latitude": 49.40506145685422,
            "longitude": 8.66955817506422
        }
    ]
]

I prepared the following POJOs to store the data into:我准备了以下 POJO 来存储数据:

public class GeoPoint {
    public double latitude;
    public double longitude;
}

... ...

public class ThreePoints {
    public List<GeoPoint> points;  
}

How do I have to change the above Jackson parser so it can handle the nested arrays?我必须如何更改上面的 Jackson 解析器才能处理嵌套数组? Can Jackson parse the data into a nested class structure such as the ThreePoints.class ? Jackson 能否将数据解析为嵌套的类结构,例如ThreePoints.class

You can simply create additional collection type.您可以简单地创建其他集合类型。 See below code:见下面的代码:

TypeFactory typeFactory = mapper.getTypeFactory();
CollectionType listType = typeFactory.constructCollectionType(List.class, contentType);
CollectionType listListType = typeFactory.constructCollectionType(List.class, listType);
List<List<GeoPoint>> readValue = mapper.readValue(json, rootCollectionType);
// convert to ThreePoints

EDIT编辑
Unfortunately you are not able to tell Jackson to convert your JSON to your POJO classes because they do not fit to each other.不幸的是,您无法告诉Jackson将您的JSON转换为您的POJO类,因为它们不适合彼此。 Jackson also does not contain annotations which you can use to map your JSON to your POJO classes. Jackson也不包含可用于将JSON映射到POJO类的注释。 You have to do it manually.你必须手动完成。 Using my code you can write custom deserializer for ThreePoints class in which you can use inner ObjectMapper and my above code.使用我的代码,您可以为ThreePoints类编写自定义反序列化器,您可以在其中使用内部ObjectMapper和我上面的代码。 I think, that you will be able easily convert List<List<GeoPoint>> readValue to ThreePoints class.我认为,您可以轻松地将List<List<GeoPoint>> readValue转换为ThreePoints类。 Another option - you can write just a simple function in you JsonUtil class.另一种选择 - 您可以在JsonUtil类中编写一个简单的函数。 If you really can not change this JSON you have to do it manually.如果您真的无法更改此JSON ,则必须手动进行。

You can write a simple custom deserializer您可以编写一个简单的自定义反序列化器

To deserialize it to your class:要将其反序列化到您的班级:

public class GeoPoint {
    public double latitude;
    public double longitude;
}

public class ThreePoints {
    public List<GeoPoint> points;
}

Write a custom deserializer:编写自定义解串器:

class ThreePointsDeserializer extends StdDeserializer<ThreePoints> {

    protected ThreePointsDeserializer() {
        super(ThreePoints.class);
    }


    @Override
    public ThreePoints deserialize(JsonParser parser, DeserializationContext ctx)
            throws IOException, JsonProcessingException {
        ThreePoints result = new ThreePoints();
        GeoPoint[] points = parser.getCodec().readValue(parser, GeoPoint[].class);
        result.points = Arrays.asList(points);
        return result;
    }
}

to use that deserializer:使用该解串器:

SimpleModule module = new SimpleModule();
module.addDeserializer(ThreePoints.class, new ThreePointsDeserializer());

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

TypeFactory tf = mapper.getTypeFactory();
CollectionType collectionType = tf.constructCollectionType(List.class, ThreePoints.class);

List<ThreePoints> result = mapper.readValue(YOUR_DATA, collectionType);

you need to read the values as Matrix, first you need to map the values using a Pojo called Place.您需要将值读取为矩阵,首先您需要使用名为 Place 的 Pojo 映射这些值。

public class Place {

    double latitude;
    double longitude;

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }
}       

Second step, you need to map the JsonNode into a Matrix.第二步,你需要将 JsonNode 映射成一个矩阵。

import java.io.IOException;
import java.util.List;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.CollectionType;
import org.codehaus.jackson.map.type.TypeFactory;


public class Main {
   static String jsonString =  "[" +
"    [" +
"        {" +
"            \"latitude\": 49.419459253939316," +
"            \"longitude\": 8.676411621072491" +
"        }," +
"        {" +
"            \"latitude\": 49.41946061080915," +
"            \"longitude\": 8.676411644939083" +
"        }," +
"        {" +
"            \"latitude\": 49.420365910782735," +
"            \"longitude\": 8.676438042403413" +
"        }" +
"    ]," +
"    [" +
"        {" +
"            \"latitude\": 49.40460334213399," +
"            \"longitude\": 8.670034018853409" +
"        }," +
"        {" +
"            \"latitude\": 49.404608057285145," +
"            \"longitude\": 8.670028775634165" +
"        }," +
"        {" +
"            \"latitude\": 49.40506145685422," +
"            \"longitude\": 8.66955817506422" +
"        }" +
"    ]" +
"]";

    public static void main(String...args) {
        final ObjectMapper om = new ObjectMapper();
        try {
           final Place[][] dtos = om.readValue(new ObjectMapper()
               .readValue(jsonString, JsonNode.class), Place[][].class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Cheers.干杯。

In my opinion the most elegant solution would be to use TypeReference在我看来,最优雅的解决方案是使用 TypeReference

ObjectMapper mapper = new ObjectMapper();
TypeReference<List<List<GeoPoint>>> typeRef = new TypeReference<List<List<GeoPoint>>>() {};
List<List<GeoPoint>> locations = mapper.readValue(jsonAsString, typeRef);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM