泽西岛:具有 1 个元素的 Json 数组被序列化为对象

2022-09-01 16:14:41

我正在使用Jersey / Java创建一个REST服务器,我发现了一个奇怪的行为。

我在服务器上有一个方法,它将对象数组作为Json返回

@GET
@Path("/files")
@Produces(MediaType.APPLICATION_JSON)
public Object getFiles() throws Exception{
    DatabaseManager db = new DatabaseManager();
    FileInfo[] result = db.getFiles();
    return result;
}

代码正确执行,数据返回到客户端(jQuery ajax 调用)。问题是,如果“result”数组具有一个或多个元素,则返回数据的格式会发生变化。

具有一个元素的响应:

{"fileInfo":{"fileName":"weather.arff","id":"10"}}

具有两个元素的响应:

{"fileInfo":[{"fileName":"weather.arff","id":"10"},{"fileName":"supermarket.arff","id":"11"}]}

如您所见,在第一种情况下,返回对象的“fileInfo”属性的值是一个对象,在第二种情况下,该值是一个数组。我做错了什么?第一个案例不应该返回这样的东西吗:

{"fileInfo":[{"fileName":"weather.arff","id":"10"}]}

即一个数组,里面有一个对象?

我知道我可以在客户端检测到这一点,但这似乎是一个非常丑陋的黑客攻击。

感谢您抽出宝贵时间接受采访。


答案 1

我最终使用了Jackson,在泽西岛官方文档(http://jersey.java.net/nonav/documentation/latest/user-guide.html#json.pojo.approach.section)中也有描述。

我以前尝试过,但它不起作用,因为我的项目的构建路径中没有jackson jar(根据文档,我认为它内置于球衣的核心库中)。

我刚刚添加了 jackson-all.jar 文件 (http://wiki.fasterxml.com/JacksonDownload),并在配置中启用了 POJO 支持

    <init-param>
          <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
          <param-value>true</param-value>
    </init-param>

瞧!


答案 2

如果您使用 JAXB 构建 JSON 结果,则可以配置 Jersey JSON 处理器以获取更重要的 JSON 格式。

泽西岛官方文件有详细的配置:

要实现更重要的 JSON 格式更改,您需要配置 Jersey JSON 处理器本身。可以在 JSONConfiguration 实例上设置各种配置选项。然后,该实例可以进一步用于创建 JSONConfigurated JSONJAXBContext,该文本充当此区域中的主要配置点。要将专用的 JSONJAXBContext 传递到 Jersey,您最终需要实现 JAXBContext ContextResolver:

    @Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class> types;
    private Class[] ctypes = { FileInfo.class}; //your pojo class
    public JAXBContextResolver() throws Exception {
        this.types = new HashSet(Arrays.asList(ctypes));
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
                ctypes); //json configuration
    }

    @Override
    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}