【问题标题】:Map an array of JSON objects to a java.util.Map and vice versa将 JSON 对象数组映射到 java.util.Map,反之亦然
【发布时间】:2015-11-25 10:45:41
【问题描述】:

问题是如何将 JSON 对象数组映射到 java.util.Map,其中每个键都是对象的某些指定属性,值是对象本身。

JSON:

{"items": [{"field1": 1, "field2": "Hello"}, {"field1": 2, "field2":"World"}]}

Java POJO:

public class Storage {
    private Map<Integer, Item> items;
}

public class Item {
    private Integer field1;
    private String field2;
}

那么有什么方法可以指定ObjectMapper 在将项目数组反序列化为Map 时,它应该使用每个JSON 对象的field1 属性作为键?

【问题讨论】:

    标签: java json fasterxml


    【解决方案1】:

    如何反序列化 JSON 字符串

    您可以使用 Jackson 反序列化 JSON 字符串:

    例如,如果您有课程Foo

    public class Foo {
    
       private Bar[] items;
    
       // Constructor / Getters & Setters
    
    } 
    

    该类有一个类数组Bar

     public class Bar {
    
         private int field1;
         private String field2;
    
    
         // Constructor / Getters & Setters
    
     }
    

    如果字段名称与您的 JSON 字符串中的名称匹配,那么您可以执行以下操作来转换它:

    String jsonString = "{\"items\": [{\"field1\": 1, \"field2\": \"Hello\"}, {\"field1\": 2, \"field2\":\"World\"}]}";
    
    ObjectMapper mapper = new ObjectMapper();
    
    Foo foo = mapper.readValue(jsonString, Foo.class);
    

    如果您使用的是 Maven,您的 pom.xml 中将需要以下依赖项:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    

    解决问题的方法:

    选项 1 - 自定义反序列化器

    编写自定义 JsonDeserializer 以将您的 JSON 字符串反序列化为 Storage 对象,其中字段 items 类型为 Map&lt;String,Item&gt;

     public class CustomDeserializer extends JsonDeserializer<Storage> {
    
        @Override
        public Storage deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                throws IOException {
    
            Map<Integer, Item> map = new HashMap<>();
    
            ObjectCodec oc = jsonParser.getCodec();
            JsonNode rootNode = oc.readTree(jsonParser);
            JsonNode items = rootNode.get("items");
    
            for (int i = 0; i < items.size(); i++) {
    
                JsonNode childNode = items.get(i);
    
                Item item = new Item(childNode.get("field1").asInt(), childNode.get("field2").asText());
    
                map.put(item.getField1(), item);
            }
    
            return new Storage(map);
        }
    }
    

    然后您将使用以下内容注释您的 Storage 类:

    @JsonDeserialize(using = CustomDeserializer.class)
    

    你的Storage 类看起来像这样;

    @JsonDeserialize(using = CustomDeserializer.class)
    public class Storage {
    
       private Map<Integer, Item> items;
    
       public Storage(Map<Integer, Item> map) {
        this.items = map;
       }
    
       ...
    
    }
    

    选项 2 - 创建 Map 后反序列化

    如开头所述,将 JSON 字符串反序列化为带有 Item 数组的 Storage 对象,然后在之后构造您的 Map&lt;Integer, Item&gt;

    希望这会有所帮助。

    【讨论】:

    • 它不能解决我的问题。我知道,如果items 只是一个数组或一些Collection,如何反序列化JSON 对象。再说一遍:我想将 items 反序列化为 Map,其中 key 是存储在 value 中的对象的属性。
    【解决方案2】:

    您可以创建自己的自定义序列化器/反序列化器来实现这一点。 Jackson 提供了一种简洁的方式来做到这一点。只需使用 @JsonDeserialize(using = YourDeserializer.class) 注释 Storage 类,并具有在 YourDeserializer 中转换 json 的逻辑。

    【讨论】:

      【解决方案3】:

      JSON 对象数组是一个 Items 数组,对吧?那么为什么不简单地将数组反序列化为 Java 的 Items 数组,然后从那里构建 Map?

      【讨论】:

      • 因为在我的例子中存在底层通用源 (DAO),它在后台使用 ObjectMapper 进行所有序列化/反序列化逻辑。我不想在那里改变任何东西。目前,使用自定义序列化器/反序列化器的解决方案似乎是实现我想要的唯一方法......
      猜你喜欢
      • 2011-06-24
      • 2017-11-17
      • 1970-01-01
      • 2018-04-03
      • 1970-01-01
      • 2018-02-05
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多