如何用Jackson解析嵌套数组?

时间:2014-06-17 21:47:05

标签: java json generics jackson multidimensional-array

我曾经成功解析过以下.json文件:

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

以下Jackson script输出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;
}

现在数据集变得更加复杂。点List成为List点的List。 我用这种方式构建它 - 如果这不正确,请纠正我。

[
    [
        {
            "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
        }
    ]
]

我准备了以下POJO来将数据存储到:

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

...

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

如何更改上面的Jackson解析器以便它可以处理嵌套数组?杰克逊能否将数据解析为嵌套的类结构,例如ThreePoints.class

4 个答案:

答案 0 :(得分:2)

您可以简单地创建其他集合类型。见下面的代码:

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

修改
很遗憾,您无法告诉JacksonJSON转换为您的POJO课程,因为它们不适合彼此。 Jackson也不包含可用于将JSON映射到POJO课程的注释。你必须手动完成。使用我的代码,您可以为ThreePoints类编写自定义反序列化器,您可以在其中使用内部ObjectMapper和我的上述代码。我想,您可以轻松地将List<List<GeoPoint>> readValue转换为ThreePoints类。另一种选择 - 你可以在JsonUtil类中编写一个简单的函数。如果你真的无法改变这个JSON,你必须手动完成。

答案 1 :(得分:1)

您可以编写一个简单的自定义反序列化器

要将其反序列化到您的班级:

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

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

编写自定义反序列化程序:

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;
    }
}

使用该反序列化器:

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);

答案 2 :(得分:0)

您需要将值读取为Matrix, 首先,您需要使用名为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;
    }
}       

第二步,您需要将JsonNode映射到Matrix。

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();
        }
    }
}

干杯。

答案 3 :(得分:0)

我认为最优雅的解决方案是使用TypeReference

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