33

假设我有一个 pojo:

import org.codehaus.jackson.map.*;

public class MyPojo {
    int id;
    public int getId()
    { return this.id; }

    public void setId(int id)
    { this.id = id; }

    public static void main(String[] args) throws Exception {
        MyPojo mp = new MyPojo();
        mp.setId(4);
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
        System.out.println(mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.WRAP_ROOT_VALUE));
        System.out.println(mapper.writeValueAsString(mp));
    }
}

当我使用 Jackson ObjectMapper 进行序列化时,我得到了

true
{"id":4}

但我想要

true
{"MyPojo":{"id":4}}

我到处搜索,杰克逊的文档真的很杂乱无章,而且大多已经过时了。

4

11 回答 11

39

@JsonTypeInfo通过在类级别添加杰克逊注释,您可以获得预期的输出。我只是在你的课堂上添加了无变化。

package com.test.jackson;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;

@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class MyPojo {
    // Remain same as you have
}

输出:

{
    "MyPojo": {
        "id": 4
    }
}
于 2015-07-01T10:23:58.580 回答
28

我没有使用杰克逊,但搜索我发现这个配置似乎是你想要的:WRAP_ROOT_VALUE

可以启用以使根值(通常是 JSON 对象,但可以是任何类型)包装在单个属性 JSON 对象中的功能,其中键作为“根名称”,由注释内省器确定(尤其是对于使用 @XmlRootElement 的 JAXB .name)或后备(非限定类名)。功能主要用于 JAXB 兼容性。

默认设置为 false,表示不包装根值。

这样您就可以配置映射器:

objectMapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);

我希望它可以帮助你...

于 2010-03-12T20:18:54.453 回答
14

以下是实现此目的的方法

Map<String, MyPojo> singletonMap = Collections.singletonMap("mypojo", mp);
System.out.println(mapper.writeValueAsString(singletonMap));

输出 {“mypojo”:{“id”:4}}

这里的好处是我们可以为 json 对象的根键提供我们的名称。通过上面的代码,mypojo将成为根密钥。当我们使用像 Mustache.js 这样的 java 脚本模板来迭代 json 对象时,这种方法将是最有用的

于 2013-06-10T02:38:31.393 回答
7

为此,您需要JsonTypeInfo在类上使用注释,特别是WRAPPER_OBJECT

@JsonTypeName("foo")                                                                                         
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT ,use = JsonTypeInfo.Id.NAME)

public class Bar(){
)
于 2018-02-01T10:20:44.630 回答
4

还有一个很好的注释:

@JsonRootName(value = "my_pojo")
public class MyPojo{
  ...
}

将产生:

{
  "my_pojo" : {...}
}
于 2016-04-17T07:47:48.870 回答
1

我使用了另一种方法,对我有用。我正在使用第三方 jar,所以我无法控制注释。所以我不得不写一些hack。

覆盖:org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(SerializationConfig, BasicBeanDescription)

添加您的属性如下

List<BeanPropertyWriter> props = super.findBeanProperties(config, beanDesc);
BeanPropertyWriter bpw = null;
try {
     Class cc = beanDesc.getType().getRawClass();
     Method m = cc.getMethod("getClass", null);
     bpw = new BeanPropertyWriter("$className", null, null, m, null,true, null);
} catch (SecurityException e) {
  // TODO
} catch (NoSuchMethodException e) {
  // TODO
}
props.add(bpw);
return props;

这样我可以得到更多的控制,也可以做其他类型的过滤器。

于 2012-03-19T14:17:54.850 回答
1

最简单的解决方案怎么样?只需使用一个包装类,如:

class Wrapper {
   public MyPojo MyPojo;
}

并在您的代码中包装/展开?

除此之外,了解您为什么想要这样的附加 json 对象条目会有所帮助?我知道这是由通过 xml api 模拟 json 的库完成的(因为 xml 和 json 之间的阻抗,由于从 xml 到 json 的转换),但对于纯 json 解决方案,通常不需要它。

是否允许您弄清楚实际类型是什么?如果是这样,也许您可​​以考虑启用多态类型信息,让杰克逊自动处理它?(有关详细信息,请参阅1.5 发行说明,PTH 条目)。

于 2010-03-22T16:40:18.890 回答
0

我很想听听 OP 对此的解决方案。我遇到了类似的问题,我的 RESTful Web 服务将对象序列化为 XML 或 JSON 以供客户端使用。Javascript 客户端需要知道包装类型以便对其进行解析。将类型与 URI 模式耦合不是一种选择。

谢谢。

编辑:我注意到 Spring MappingJacksonJsonMarshaller 在编组时添加了包装类,所以我在调试中单步执行代码并注意到 Spring 传入一个带有单个键值对的 HashMap,这样键是包装名称,值是目的。因此,我扩展了 JacksonJaxbJsonProvider,重写了 writeTo() 方法并添加了以下内容:

HashMap<String, Object> map = new HashMap<String, Object>();
map.put(value.getClass().getSimpleName(), value);
super.writeTo(map, type, genericType, annotations, mediaType, httpHeaders,entityStream);

这有点像黑客,但效果很好。

于 2010-04-30T15:30:49.270 回答
0

我通过经验发现,所有 JSON 都包含后端类型(作为字符串)和用于在前端呈现它的组件类型(如果使用 angular 或 Vue 之类的东西)是一个好主意。

这样做的理由是您可以使用一组代码处理各种类型。

例如,在 vue 中,在数据中包含 UI 组件的名称允许您在屏幕上仅使用父模板中的单个标记来呈现不同类型的子项列表。

  <component :is="child.componentType"/>.

对于后端系统和 Web 服务 - 我更喜欢使用单个 Web 服务处理器类,它通过根据传入的有效负载查找适当的处理器类来为所有 Web 服务提供日志记录、审计和异常处理。这使得我的所有 Web 服务的实现看起来完全相同(大约 3 行代码),并且我在调用的生命周期中获得了详细的事件日志记录,而无需编写任何每个服务代码来这样做。

具有包装 JSON 的类型使其自我记录。如果您看到的只是属性,那么在找到相应的端点之前,您根本不知道自己在看什么。

如果您想编写数据驱动的软件,能够识别您正在处理的内容是一项基本要求。

于 2018-08-13T21:13:21.127 回答
0
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME) 

正如 Arun Prakash 所建议的那样,此注释非常有效。我试图以这种形式获取 json:

{"Rowset":{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}

但变成这样:

{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}

现在该注释解决了我的问题。

于 2016-06-16T04:13:45.230 回答
0

与根名称一起使用。

objectMapper.writer().withRootName(MyPojo.class.getName());
于 2017-07-14T09:32:14.140 回答