Jersey子资源将我的API包装在一个额外的JSON层中 - 为什么我要这个?

时间:2015-10-03 23:29:23

标签: java json jersey jersey-2.0 dropwizard

作为一个例子,让我们假设我正在创建一个行为如下的HTTP REST API:

归还所有员工的集合:

GET /employees/

[
    {
        "id": 1,
        "name": "John",
        "roles": [
            {
                "id": 20,
                "responsibility": 1000
            },
            ...
        ]
    },
    ...
]

返回身份1的员工代表:

GET /employees/1/

{
    "id": 1,
    "Name": "John",
    "roles": [
        {
            "id": 20,
            "responsibility": 1000
        },
        ...
    ]
}

返回员工角色的集合:

GET /employees/1/roles

[
    {
        "id": 20,
        "responsibility": 1000
    },
    ...
]

返回ID为20的角色代表:

GET /employees/1/roles/20

{
    "id": 20,
    "responsibility": 1000
}

通过这种方式,我们可以遍历员工表示的树。除了/ roles之外,还有许多其他员工端点。

使用Jersey我将其拆分为具有多个子资源的根资源,例如:

@Path("/employees")
public class EmployeesResource() {
    ...
    @GET
    @Path("/{employeeId}/roles")
    public RolesResource getRoles(@PathParam("employeeId") long employeeId) {
        return new RolesResource(employeeId);
    }
}

当我获得/employees/employees/1时,这会产生所需的JSON结果,但是当我获得/employees/1/roles时,我得到了响应主体:

{
    "roles": [
        {
            "id": 20,
            "responsibility": 1000
        },
        ...
    ]
}

Jersey已将我的角色表示集合包装在某个对象中。注意:该对象似乎连接到RolesResource中的子资源资源方法的名称(例如,如果方法名为getRoles(),我得到{"roles": [...]},如果方法名为getFoo()我得到{"foo": [...]})。

我的问题:泽西有这么做的原因。为什么我要将我的表示包裹起来呢?如果没有充分的理由,我怎么能摆脱这个?

编辑:我使用的是Dropwizard版本0.8.2,它看起来像from maven正在拉动泽西2.19。它使用Jackson作为JSON提供者 - 再次,从maven看起来它的版本是2.5.1。没有web.xml,因为这是一个dropwizard应用程序。

2 个答案:

答案 0 :(得分:0)

我不知道dropwizard但我知道jackson我现在正在使用jersey 2.21,所以我希望我的设置足够关闭。

我猜你构建的RolesResource类与此类似(如果不是这样,请发布它!)

public class RolesResource {
    private Role[] roles;

    //constructor, getters, setters...
}

其中Role就像是,

public class Role {
    private Integer id;
    private Integer responsibility;

    //constructor, getters, setters...
}

如果是这种情况,如果您将RolesResource作为服务的输出返回,则只需获得您描述的json

{
    "roles": [
        {
           ...
        },
        ...
    ]
}

因为该对象实际上是一个名为Role[]的数组roles

但是,您也可以返回Role[]作为服务的输出,

@Path("/employees")
public class EmployeesResource() {
    ...
    @GET
    @Path("/{employeeId}/roles")
    public Role[] getRoles(@PathParam("employeeId") long employeeId) {
        return (new RolesResource(employeeId)).getRoles();
    }
}

然后输出将只是Role类型的对象数组。

[
    {
        "id": ...,
        "responsibility": ...
    },
    ...
]

至于你的问题,是否要比另一个更有意义?我想这是一个选择问题;我通常更喜欢封装,以便在客户端检查更容易(因此我选择第一个解决方案),但我认为它不会产生很大的影响。

希望它有所帮助。

答案 1 :(得分:0)

我明白了。我用EmployeesResource.getRoles()注释了子资源定位器(在此示例中为@GET)。删除该注释会产生所需的结果。 RolesResource中的方法使用HTTP方法名称进行注释。