java - 反序列化 JSON - 嵌套列表和键需要作为值

标签 java json key-value json-deserialization

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

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

我的目标是获取具有货币、价格突破和价格属性的每个价格的对象。

我不知道如何执行该操作。我尝试了以下方法:

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

  2. 反序列化就像

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

(受到此 Deserializing Jackson by using a key as value 的启发,但也不起作用)

  • 使用这样的包装器:

    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 读取成功)。我找不到任何其他方法来处理这个问题(一些自定义反序列化器?)。

    编辑

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

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

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

    非常感谢。

    最佳答案

    是的,自定义解串器可以工作。

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

    关于java - 反序列化 JSON - 嵌套列表和键需要作为值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45171601/

    相关文章:

    Java:哈希表在一个桶中存储具有相同哈希值的多个项目

    Java 机器人 - 检查符号键

    mysql - SQL 替换所有指定的键

    java - REST - 使用 Spring MVC 返回创建的对象

    python - 搜索字典以获取每个键的完整路径

    java - 将 onClickListener 设置为大量 View

    javascript - jQuery ajax 自动完成不映射

    node.js - Node.js 的最快、非基于内存的多进程键值存储

    python-3.x - 如何在 Python 中更新文本文件的值

    扩展可比较的 Java 泛型类不能转换为 java.base/[Ljava.lang.Comparable