【问题标题】:How to wrap a List as top level element in JSON generated by Jackson如何将列表包装为杰克逊生成的 JSON 中的顶级元素
【发布时间】:2013-04-15 18:58:33
【问题描述】:

我遇到了一个问题,我试图包含一个 List 作为根节点,但我似乎无法得到这个。让我解释。假设我们有一个类“TestClass”

class TestClass{
    String propertyA;       
}

现在,在一些实用方法中,这就是我所做的

String utilityMethod(){
   List<TestClass> list = someService.getList();
   new ObjectMapper().writeValueAsString(list); 
}

我试图在 JSON 中得到的输出是

{"ListOfTestClasses":[{"propertyA":"propertyAValue"},{"propertyA":"someOtherPropertyValue"}]}

我试过用

objMapper.getSerializationConfig().set(Feature.WRAP_ROOT_VALUE, true);

但是,我似乎仍然没有做对。

现在,我正在创建一个 Map ,我编写它是为了实现我想要做的事情,这很有效,但显然这是一个 hack。有人可以帮我一个更优雅的解决方案吗?谢谢

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    不幸的是,即使启用了WRAP_ROOT_VALUE 功能,您仍然需要额外的逻辑来控制在序列化 Java 集合时生成的根名称(请参阅this answer 了解详细原因)。这让您有以下选择:

    • 使用持有者类来定义根名称
    • 使用地图。
    • 使用自定义ObjectWriter

    这里有一些代码说明了三个不同的选项:

    public class TestClass {
        private String propertyA;
    
        // constructor/getters/setters
    }
    
    public class TestClassListHolder {
    
        @JsonProperty("ListOfTestClasses")
        private List<TestClass> data;
    
        // constructor/getters/setters
    }
    
    public class TestHarness {
    
        protected List<TestClass> getTestList() {
            return Arrays.asList(new TestClass("propertyAValue"), new TestClass(
                    "someOtherPropertyValue"));
        }
    
        @Test
        public void testSerializeTestClassListDirectly() throws Exception {
            final ObjectMapper mapper = new ObjectMapper();
            mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
            System.out.println(mapper.writeValueAsString(getTestList()));
        }
    
        @Test
        public void testSerializeTestClassListViaMap() throws Exception {
            final ObjectMapper mapper = new ObjectMapper();
            final Map<String, List<TestClass>> dataMap = new HashMap<String, List<TestClass>>(
                    4);
            dataMap.put("ListOfTestClasses", getTestList());
            System.out.println(mapper.writeValueAsString(dataMap));
        }
    
        @Test
        public void testSerializeTestClassListViaHolder() throws Exception {
            final ObjectMapper mapper = new ObjectMapper();
            final TestClassListHolder holder = new TestClassListHolder();
            holder.setData(getTestList());
            System.out.println(mapper.writeValueAsString(holder));
        }
    
        @Test
        public void testSerializeTestClassListViaWriter() throws Exception {
            final ObjectMapper mapper = new ObjectMapper();
            final ObjectWriter writer = mapper.writer().withRootName(
                    "ListOfTestClasses");
            System.out.println(writer.writeValueAsString(getTestList()));
        }
    }
    

    输出:

    {"ArrayList":[{"propertyA":"propertyAValue"},{"propertyA":"someOtherPropertyValue"}]}
    {"ListOfTestClasses":[{"propertyA":"propertyAValue"},{"propertyA":"someOtherPropertyValue"}]}
    {"ListOfTestClasses":[{"propertyA":"propertyAValue"},{"propertyA":"someOtherPropertyValue"}]}
    {"ListOfTestClasses":[{"propertyA":"propertyAValue"},{"propertyA":"someOtherPropertyValue"}]}

    使用ObjectWriter 非常方便 - 请记住,所有用它序列化的顶级对象都将具有相同的根名称。如果那不是可取的,那么请改用地图或持有人类。

    【讨论】:

      【解决方案2】:

      我希望基本的想法是这样的:

      class UtilityClass {
          List listOfTestClasses;
          UtilityClass(List tests) {
              this.listOfTestClasses = tests;
          }
      }
      
      String utilityMethod(){
          List<TestClass> list = someService.getList();
          UtilityClass wrapper = new UtilityClass(list);
          new ObjectMapper().writeValueAsString(wrapper); 
      }
      

      【讨论】:

      • 这真的是最好的解决方案吗?
      • 它与我目前使用的“地图”解决方案非常相似。
      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多