【问题标题】:REST GET list as JSONREST GET 列表为 JSON
【发布时间】:2016-12-05 18:57:12
【问题描述】:

我有一个 id 列表,我需要将其作为参数传递,以便以 JSON 格式显示。具体来说,我将值放在一个列表中,并希望我的 GET 方法将它们返回为:

[ 1, 5, 12,...]

我尝试使用 GenericList,但收到 MessageBodyWriter 错误:

MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List<java.lang.Long>.

我使用的是 Jersey 2.16,输出自定义类列表没有问题。代码在这里:

@GET
@Path("{name}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(@PathParam("name") String name){
    List<Long> userIds = userService.getUserssByName(name);
    GenericEntity<List<Long>> list = new GenericEntity<List<Long>>(userIds){};
    return Response.ok(list).build();
}

UserService 查询名称与某个名称匹配的所有用户的 hashmap 并返回其键列表:

public List<Long> getUserssByName(String name){
    List<Long> ids = new ArrayList<>();

    for (Entry<Long, User> entry : users.entrySet()){
        User user = entry.getValue();
        if (user.getName().equals(name)){
            ids.add(entry.getKey());
        }
    }

    return ids;
}

如前所述,我怎样才能显示该列表?

【问题讨论】:

标签: java json rest jersey


【解决方案1】:

您必须将列表转换为数组。

@GET
@Path("{name}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(@PathParam("name") String name){
    List<Long> userIds = userService.getUserssByName(namee);
    Long[] userIdArray = userIds.toArray();
    return Response.ok(userIdArray).build();
}

【讨论】:

  • 你不应该返回一个 JSON 字符串,而不是一个 Long 数组吗?
  • jersy 会自动转换这个。实际上它会通过反序列化 this 来发送 Response 对象的 Json 表示。
  • 由于某种原因,这会引发异常:[Ljava.lang.Object;不能以根本原因转换为 [Ljava.lang.Long;]
  • @Flopn 对,我就是这么想的。无需额外的转换,Response.ok 采用 Object 参数。
【解决方案2】:

我认为这个解释答案会比仅仅“修复”你的代码更好

默认情况下,jersey 提供一组实体提供程序,可用于给定的媒体类型。对于application/json,默认提供以下类型:

byte[]
String
InputStream
Reader
File
DataSource
StreamingOutput

使用您当前使用的工具,将其他类型的序列化支持添加到 json 有点困难。我会解释...

Jersey 只是一个用于在 Java 中开发 RESTful Web 服务的框架。曾经有一段时间 REST 不存在(或不被视为有用),在这个概念出现之前,已经有许多具体的实现来促进 Http 数据传输。 JAX-RS 就是其中之一。那是在 javascript 可能还处于起步阶段,而 XML 在很大程度上统治着万维网的时期。 JAX-RS 的设计初衷不是为了防止类型擦除,而类型擦除正是我们想要实现的目标。对我来说,通过极其冗长的解决方案来实现 MessageBodyWriter 中的行为将是重新发明轮子,没有人喜欢重新发明轮子!但是,如果您有兴趣编写自己的实体,或者您有兴趣了解实体是什么以及如何自定义它们,请前往https://jersey.java.net/documentation/latest/message-body-workers.html。阅读本文档将概述您的问题到底发生了什么。

解决方案

选择一项服务。学习它,不要重新发明轮子。有许多服务可以实现这一目标。我最喜欢的工具是 Gson。它是由 Google 开发的 Java 库,用于将 Java 对象转换为其 JSON 表示形式,反之亦然。

想知道修复代码有多简单吗?

@GET
@Path("{name}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(@PathParam("name") String name){
    List<Long> userIds = userService.getUserssByName(namee);
    Type listType = new TypeToken<List<Long>>() {}.getType();
    Gson gson = new Gson();
    String userIdList = gson.toJson(userIds, listType);
    return Response.ok(userIdList).build();
}

现在,jersey 支持用于字符串实体响应的 application/json。您几乎所有的响应都将表示为字符串,防止类型擦除,您将成为一个更快乐的开发人员。

希望这会有所帮助!

【讨论】:

  • 可以将转换为 Json 的代码提取到可重用的 MessageBodyWriter 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 2020-09-27
  • 2014-09-01
相关资源
最近更新 更多