【问题标题】:Deserialize JSON in Jackson where key is a value在 Jackson 中反序列化 JSON,其中键是一个值
【发布时间】:2018-08-18 10:21:53
【问题描述】:
{
  {
      "1234": {
          "name": "bob"
      }
  },
  {
      "5678": {
          "name": "dan"
      }
  }
}

我有一个代表名称的类(和其他字段,我只是简单地回答了这个问题)。但是每个元素都以人的身份作为键。

我尝试了几件事,包括:

class Name {
     String Name;
     //getter and setter
}
class NameId {
     String id;
     Name name;
     //getter and setters
}

//json is the string containing of the above json
ArrayList<NameId> map = objectMapper.readValue(json, ArrayList.class);
for (Object m : map) {
    LinkedHashMap<String, NameId> l = (LinkedHashMap)m;
            Map<String, NameId> value = (Map<String, NameId>) l;

            //System.out.println(l);
            //System.out.println(value);
            for (Object key : value.keySet()) {
                System.out.println("key: " + key);
                System.out.println("obj: " + value.get(key));

                NameId nameId = (NameId)value.get(key);

            }
}

我的问题是它不允许转换为 NameId。我得到的错误是:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to NameId

关于正确解析这样一个 json 字符串的最佳方法有什么想法吗?

【问题讨论】:

  • 你的 JSON 格式肯定是错误的。
  • 不需要强制转换。而你双重投射,我不明白。
  • 更新了 json,我试过用 [] 和 {}

标签: java json jackson json-deserialization


【解决方案1】:

不需要自定义反序列化器。

首先,@klaimmore 建议的 json 文件(命名为 test.json):

{
    "1234": {
        "name": "bob"
    },
    "5678": {
        "name": "dan"
    }
}

其次。这是 2 个单独的类文件:

@JsonDeserialize
public class Name {
    String name;

    public Name(String name) {
        this.name = name;
    }
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
}

@JsonDeserialize
public class NameId {
    Name name;
    String id;
    /**
     * @return the id
     */
    public String getId() {
        return id;
    }
    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }
    /**
     * @return the name
     */
    public Name getName() {
        return name;
    }
    /**
     * @param name the name to set
     */
    public void setName(Name name) {
        this.name = name;
    }
}

以及额外的简单 json 解析器类。

public class JsonParser {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        String jsonString = new String(Files.readAllBytes(Paths.get("test.json")));
        ObjectMapper mapper = new ObjectMapper();
        Map<String,NameId> nameIdList = mapper.readValue(jsonString, new TypeReference<Map<String,NameId>>(){});
        nameIdList.entrySet().forEach(nameIdEntry -> System.out.println("name id is: " + nameIdEntry.getKey() + 
                " and name is: " + nameIdEntry.getValue().getName().getName()));

    }

}

还有。这几乎是How to convert json string to list of java objects 的欺骗。你应该阅读这篇文章。

【讨论】:

    【解决方案2】:

    您的 json 格式错误。您需要在它周围加上方括号,否则它不被视为 json 数组。如果您的 json 看起来像(例如)

    [
        {
            "1234" : {
                "name" : "dan"
            }
        },
        {
            "5678" : {
                "name" : "mike"
            }
        }
    ]
    

    您可以为对象映射器编写自定义反序列化器。请参阅下面的工作示例:

    public static void main(String... args) throws Exception {
        String testJson = "[{ \"1234\" : { \"name\" : \"dan\" } },{ \"5678\" : { \"name\" : \"mike\" } }]";
    
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(NameId.class, new MyDeserializer());
        mapper.registerModule(module);
        ArrayList<NameId> map = mapper.readValue(testJson.getBytes(), new TypeReference<List<NameId>>() {
        });
        for (NameId m : map) {
            System.out.println(m.id);
            System.out.println(m.name.name);
            System.out.println("----");
        }
    }
    
    
    @JsonDeserialize(contentUsing = MyDeserializer.class)
    static class NameId {
         String id;
         Name name;
         //getter and setters
        }
    
    static class Name {
         String name;
         //getter and setter
    }
    
    static class MyDeserializer extends JsonDeserializer<NameId> {
    
        @Override
        public NameId deserialize(JsonParser p, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            JsonNode node = p.getCodec().readTree(p);
            Map.Entry<String, JsonNode> nodeData = node.fields().next();
            String id = nodeData.getKey();
            String name = nodeData.getValue().get("name").asText();
            Name nameObj = new Name();
            nameObj.name = name;
            NameId nameIdObj = new NameId();
            nameIdObj.name = nameObj;
            nameIdObj.id = id;
            return nameIdObj;
        }
    }
    

    【讨论】:

    • 这真的很糟糕。您只需要 1 行代码!
    • 在这个解决方案上,我在 .fields() 上收到一个编译错误,说“JsonNode 类型的方法 fields() 未定义”。我将其更改为 getFields 并出现运行时错误:java.util.NoSuchElementException
    • 你使用什么依赖?
    • 那些看起来很旧。我使用:编译组:'com.fasterxml.jackson.core',名称:'jackson-core',版本:'2.9.4' 编译组:'com.fasterxml.jackson.core',名称:'jackson-databind ', version: '2.9.4' 你能更新它们吗?
    • 更新我的版本并添加方括号后,此答案有效,谢谢!
    【解决方案3】:

    您的 json 无效。也许有点不同:

    {
        "1234": {
            "name": "bob"
        },
        "5678": {
            "name": "dan"
        }
    }
    

    你可以建模如下:

    class Person {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    不要尝试使用列表,而是使用地图:

    Map<Integer, Person> map = new ObjectMapper().readValue(json,
        TypeFactory.defaultInstance()
                .constructMapType(Map.class, Integer.class, Person.class));
    

    【讨论】:

    • 这比必要的复杂得多
    【解决方案4】:

    试试这个

    Iterator<String> iterator1 =outerObject.keys();
    while(iterator1.hasNext())
    {
    JsonObject innerObject=outerObject.getJsonObject(iterator1.next());
    Iterator<String> iterator2=innerObject.keys();
    while(iterator2.hasNext()){
    String name=innerObject.getString(iterator2.next());
    }
    } 
    

    【讨论】:

    • 这不是一个好的解决方案。为什么要从 jackson & fasterxml 切换到简单的 json 以获得这样的解决方案?这比需要的代码多得多
    • 这确实比较复杂
    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 2021-06-11
    • 2021-05-01
    • 1970-01-01
    • 2023-03-04
    • 2014-10-14
    相关资源
    最近更新 更多