【问题标题】:Deserialize JSON - nested lists and key needed as value反序列化 JSON - 需要作为值的嵌套列表和键
【发布时间】:2017-07-19 18:46:10
【问题描述】:

我需要在 Java 1.7 中使用 Jackson 反序列化这个,使用货币作为值:

"prices": {
    "USD": [
        [1, "1.99000"],
        [100, "1.89000"],
        [1000, "1.40500"]
    ],
    "EUR": [
        [1, "1.53000"],
        [100, "1.45000"],
        [1000, "1.08350"]
    ]
}

(来源是这个 REST API https://octopart.com/api/docs/v3/rest-api#notes-partoffer.prices

我的目标是为每个 Price 获取具有货币、价格中断和价格属性的对象。

我不知道该怎么做。我尝试了以下方法:

  1. 将整个“价格”反序列化为字符串以供进一步处理(不起作用,无法从 START_OBJECT 令牌中反序列化 java.lang.String 的实例 - 显然,因为这是 JSON_OBJECT)

  2. 反序列化

    LinkedHashMap<String, LinkedHashMap<Integer, String>>>
    

(受此 Deserializing Jackson by using a key as value 启发,但也没有用)

  1. 使用这样的包装器:

    public class PartOfferPriceWrapper {
    
    private LinkedHashMap<String, List<Entry<Integer, String>>> prices;
    
    }
    

然后处理如下:

List<PartOfferPrice> partOfferPriceList = new ArrayList<PartOfferPrice>();

  for (Entry<String, List<Entry<Integer, String>>> currencyEntry : 
    partOfferPrices.entrySet()) {

      for (Entry<Integer, String> priceEntry : currencyEntry.getValue()) {
        PartOfferPrice partOfferPrice = new PartOfferPrice();

        partOfferPrice.setOffer_id(partOfferId);
        partOfferPrice.setCurrency(currencyEntry.getKey());
        partOfferPrice.setPriceBreak(priceEntry.getKey());              

        partOfferPrice.setPrice(Double.parseDouble(priceEntry.getValue()));

        partOfferPriceList.add(partOfferPrice);
        }

这看起来不错,但结果是空的(这是更大响应的一部分,使用 Response.readEntity 读取成功)。我找不到任何其他方法来处理这个(一些自定义反序列化器?)。

编辑

我尝试按照 tima 的建议使用自定义反序列化器:

    public class PartOfferPricesWrapperDeserializer extends 
    JsonDeserializer<PartOfferPricesWrapper> {

    public PartOfferPricesWrapperDeserializer() { super(); }

    @Override
    public PartOfferPricesWrapper deserialize(JsonParser jsonParser, 
        DeserializationContext context) throws IOException, 
        JsonProcessingException {

        PartOfferPricesWrapper partOfferPricesWrapper = new 
        PartOfferPricesWrapper();
        List<PartOfferPrice> priceList = new ArrayList<PartOfferPrice>();

        JsonNode node = jsonParser.readValueAsTree();

        Iterator<Entry<String, JsonNode>> nodes = 
        node.get("prices").fields();

        while (nodes.hasNext()) {               
            Map.Entry<String, JsonNode> entry = nodes.next();               
            for (JsonNode tempNode : entry.getValue()) {

                PartOfferPrice price = new PartOfferPrice();
                price.setCurrency(entry.getKey());

                for (int i = 0; i < tempNode.size(); i++) {

                    if (tempNode.get(i).isInt()) {
                        price.setPriceBreak(tempNode.get(i).intValue());                            
                    }
                    else
                    {
                        price.setPrice(tempNode.get(i).asDouble());                         
                    }                                           
                }

            priceList.add(price);
            }
        }
        partOfferPricesWrapper.setPrices(priceList);
        return partOfferPricesWrapper;
    }
}

将此添加到处理程序方法中:

    SimpleModule module = new SimpleModule();
    module.addDeserializer(PartOfferPricesWrapper.class, new 
    PartOfferPricesWrapperDeserializer());
    objectMapper.registerModule(module);          

    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
    false);
    partsMatchResponse = objectMapper.readValue(target.getUri().toURL(), 
    PartsMatchResponse.class);

如果响应仅包含“价格”节点,这可能会起作用,但现在我在 node.get(“价格”).fields() 上得到 NullPointerException;它可能试图解析整个响应,但我只需要对“价格”部分使用自定义反序列化器。有可能吗?

非常感谢。

【问题讨论】:

    标签: java json key-value json-deserialization


    【解决方案1】:

    是的,自定义反序列化器可以工作。

    class CustomDeserializer extends JsonDeserializer<Prices> {
    
        public CustomDeserializer() { super(); }
    
        @Override
        public Prices deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
            JsonNode node = jsonParser.readValueAsTree();
    
            Iterator<Entry<String, JsonNode>> nodes = node.get("prices").fields();
    
            while (nodes.hasNext()) {
                Map.Entry<String, JsonNode> entry = nodes.next();
    
                System.out.println(entry.getKey());
    
                for (JsonNode tempNode : entry.getValue()) {
                    for (int i = 0; i < tempNode.size(); i++) {
                        System.out.println(tempNode.get(i).getClass() + "\t" + tempNode.get(i));
                    }
                }
    
                System.out.println();
            }
    
            return null;
        }
    }
    

    输出

    USD
    class com.fasterxml.jackson.databind.node.IntNode   1
    class com.fasterxml.jackson.databind.node.TextNode  "1.99000"
    class com.fasterxml.jackson.databind.node.IntNode   100
    class com.fasterxml.jackson.databind.node.TextNode  "1.89000"
    class com.fasterxml.jackson.databind.node.IntNode   1000
    class com.fasterxml.jackson.databind.node.TextNode  "1.40500"
    
    EUR
    class com.fasterxml.jackson.databind.node.IntNode   1
    class com.fasterxml.jackson.databind.node.TextNode  "1.53000"
    class com.fasterxml.jackson.databind.node.IntNode   100
    class com.fasterxml.jackson.databind.node.TextNode  "1.45000"
    class com.fasterxml.jackson.databind.node.IntNode   1000
    class com.fasterxml.jackson.databind.node.TextNode  "1.08350"
    

    你可以在反序列化器中创建你想要的对象和结构(Prices是我使用的一个空类)。

    编辑

    您可以对字段使用相同的自定义反序列化程序,只需稍作改动。

    前两行如下所示,因为您不需要查找 prices 节点,因为当它反序列化字段时,它只会传递该字段的 JSON。其余行相同。

    JsonNode node = jsonParser.readValueAsTree();
    Iterator<Entry<String, JsonNode>> nodes = node.fields();
    

    然后在你的包装类中:

    class PricesWrapper {
    
        // ...
    
        @JsonDeserialize(using = CustomDeserializer.class)
        private Prices prices;
    
        // ...
    }
    

    【讨论】:

    • 好的,谢谢,我会试试的。但是由于 Price 只是响应的一小部分(与 PriceOffer 相关,与 Part 相关,但都是一大块数据),看来我必须自定义反序列化整个响应?
    • @budul 不客气。我已经编辑了字段反序列化的问题。
    • 蒂玛,它有效!我非常感谢您的帮助,因为我花了将近两天的时间试图解决它,今天我应该展示一些结果......只有一件事让我烦恼 - 我无法自己解决它:-)(甚至必须注册所以...)。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2019-06-13
    • 2019-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多