【问题标题】:Jackson JSON key as value in JavaJackson JSON键作为Java中的值
【发布时间】:2017-10-27 22:36:06
【问题描述】:

我在 Spring MVC 应用程序中使用 Jackson。我想使用 String 值作为 Java POJO 的键名 --> JSON

"record": {
        "<Dynamic record name String>": {
          "value": { 
          ....
          }
      }
 }     

因此动态记录名称字符串可以是“abcd”、“xyz”或任何其他字符串值。如何定义我的“记录”POJO 以拥有这样的键?

【问题讨论】:

  • 将其映射到字典/HashMap?使用自定义序列化? POJO 字段本身是固定名称
  • 你能多解释一下地图方法吗?然后它不会使用地图字段的属性名称进行序列化吗?我不想要自定义序列化程序,因为我主要使用带有任何 Jackson 注释的 POJO,所以对于这种情况,除非必要,否则我不想要

标签: java spring serialization jackson


【解决方案1】:

很遗憾,Java 类中不能有 动态 字段(与其他一些语言不同),因此您有两种选择:

  1. 使用Maps
  2. 使用 JSON 对象(即 JsonNode 在 Jackson 的情况下)

假设,你有这样的数据:

{
    "record": {
        "jon-skeet": {
            "name": "Jon Skeet",
            "rep": 982706
        },
        "darin-dimitrov": {
            "name": "Darin Dimitrov",
            "rep": 762173
        },
        "novice-user": {
            "name": "Novice User",
            "rep": 766
        }
    }
}

创建两个类来捕获它,一个用于用户,另一个用于对象本身:

User.java

public class User {
    private String name;
    private Long rep;

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public Long getRep() { return rep; }

    public void setRep(Long rep) { this.rep = rep; }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", rep=" + rep +
                '}';
    }
}

Data.java

public class Data {
    private Map<String, User> record;

    public Map<String, User> getRecord() { return record; }

    public void setRecord(Map<String, User> record) { this.record = record; }

    @Override
    public String toString() {
        return "Data{" +
                "record=" + record +
                '}';
    }
}

现在,解析 JSON(我假设类路径的根目录中有一个 data.json 文件):

public class App {
    public static void main(String[] args) throws Exception {
        final ObjectMapper objectMapper = new ObjectMapper();

        System.out.println(objectMapper.readValue(App.class.getResourceAsStream("/data.json"), Data.class));
        System.out.println(objectMapper.readTree(App.class.getResourceAsStream("/data.json")));
    }
}

这将输出:

Data{record={jon-skeet=User{name='Jon Skeet', rep=982706}, darin-dimitrov=User{name='Darin Dimitrov', rep=762173}, novice-user=User{name='Novice User', rep=766}}}
{"record":{"jon-skeet":{"name":"Jon Skeet","rep":982706},"darin-dimitrov":{"name":"Darin Dimitrov","rep":762173},"novice-user":{"name":"Novice User","rep":766}}}

如果是Map,您可以使用一些静态类,例如在这种情况下的User,或者使用Maps of Maps (Map&lt;String, Map&lt;String, ...&gt;&gt;) 完全动态化。但是,如果您发现自己使用太多地图,考虑切换到JsonNodes。基本上,它们与Map 相同,并且是专门为高动态数据“发明”的。不过,以后你会很难使用它们...

看一个完整的例子,我已经为你准备好了here

【讨论】:

  • 太棒了!非常感谢!
【解决方案2】:

这是在 Kotlin 中,但我使用 Jackson 找到了解决相同问题的方法。

您不需要根节点“记录”,因此您需要摆脱它或更深入地启动一个节点(您自己在那里),但要打开作为其子节点的记录列表id 到对象中带有 id 的记录列表如下:

    val node = ObjectMapper().reader().readTree(json)

    val recordList = mutableListOf<Record>()
    node.fields().iterator().forEach {
        val record = record(
                it.key,
                it.value.get("name").asText(),
                it.value.get("rep").asText()
        )

        recordList.add(event)
    }

node.fields() 返回子节点的映射(也是映射)

遍历父映射,您将从键中获取 id,然后嵌套数据在值中(这是另一个映射)

每个子字段都是键:值在哪里

key = record id
value = nested data (map)

这个解决方案,你不需要多个类来反序列化一个类列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多