使用Jackson将Java对象序列化为JSON时,抑制包装器对象
我有一个Web服务,返回一个列表作为JSON。 它使用Jackson将Java POJO列表映射到JSON。 问题是JSON表示在数组周围有一个包装器对象,我只想要数组。 即,我得到了这个:
{"optionDtoList":[{...}, ..., {...}]}
当我真正想要的是这个:
[{...}, ..., {...}]
我正在直接序列化Java List; 我没有用包装器对象包装List并序列化包装器对象。 jackson似乎正在添加JavaScript包装器对象。
我假设我可以在POJO上使用一些注释来抑制包装器对象,但我没有看到它。
对解决方案的限制
我想在服务端解决这个问题,而不是剥掉客户端上的包装器。 客户端是一个jQuery UI小部件(自动完成小部件,并不重要),它需要一个简单的数组,我不想修改小部件本身。
我试过的
- 我尝试用Java POJO数组替换Java POJO列表,结果是一样的。
- 我试过
@JsonTypeInfo(use = Id.NONE)
认为这可能会抑制包装器,但它没有。
在我运行的测试模式中:
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper(); String json = mapper.writeValueAsString( Arrays.asList("one","two","three","four","five") ); System.out.println(json);
收益:
["one","two","three","four","five"]
这是你期待的行为吗?
我可以看到,当我通过Spring控制器返回此列表并让MappingJacksonJsonView处理将列表转换为json时,是的,它周围有一个包装器,它告诉我MappingJacksonJsonView是添加包装器的那个。 然后,一种解决方案是从控制器显式返回json,例如:
@RequestMapping(value = "/listnowrapper") public @ResponseBody String listNoWrapper() throws Exception{ ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(Arrays.asList("one","two","three","four","five")); }
我遇到了和你一样的问题。
在方法声明中将@ResponseBody添加到我的列表前面后,问题就解决了。
例如:
public @ResponseBody List
你可以写自定义序列化器:
public class UnwrappingSerializer extends JsonSerializer
它将忽略深度低于指定的外部对象(默认为2)。
然后使用如下:
public class UnwrappingSerializerTest { public static class BaseT1 { public List getTest() { return test; } public void setTest(List test) { this.test = test; } private List test; } @JsonSerialize(using = UnwrappingSerializer.class) public static class T1 extends BaseT1 { } @JsonSerialize(using = UnwrappingSerializer.class) public static class T2 { public BaseT1 getT1() { return t1; } public void setT1(BaseT1 t1) { this.t1 = t1; } private BaseT1 t1; } @Test public void test() throws IOException { ObjectMapper om = new ObjectMapper(); T1 t1 = new T1(); t1.setTest(Arrays.asList("foo", "bar")); assertEquals("[\"foo\",\"bar\"]", om.writeValueAsString(t1)); BaseT1 baseT1 = new BaseT1(); baseT1.setTest(Arrays.asList("foo", "bar")); T2 t2 = new T2(); t2.setT1(baseT1); assertEquals("{\"test\":[\"foo\",\"bar\"]}", om.writeValueAsString(t2)); } }
笔记:
- 它只需要单个字段包装器,并且会在
{{field1: {...}, field2: {...}}
类的内容上生成无效的JSON - 如果您使用自定义
SerializerFactory
您可能需要将其传递给序列化程序。 - 它使用单独的串行器缓存,因此这也是一个问题。
老实说,我不会太快尝试解决这个问题,因为包装器会创建一个代码更具可扩展性的情况。 如果您将来扩展它以返回其他对象,那么使用此Web服务的客户很可能不需要更改实现。
但是,如果所有客户端都期望一个未命名的数组,那么将来在该数组之外添加更多属性可能会破坏统一接口。
话虽如此,每个人都有理由想要以某种方式做某事。 您正在序列化的对象是什么样的? 您是在序列化包含数组的对象,还是在序列化实际的数组本身? 如果您的POJO包含一个数组,那么解决方案可能是将数组拉出POJO并代之以序列化数组。
我在尝试解决同样的问题时偶然发现了这个问题,但是没有使用@ResponseBody方法,但仍然在我的序列化JSON中遇到“包装器”。 我的解决方案是将@JsonAnyGetter添加到方法/字段,然后包装器将从JSON中消失。
显然这是一个已知的jacksonbug /解决方法: http : //jira.codehaus.org/browse/JACKSON-765 。