在Jersey服务中使用JSON对象

Ste*_*eve 33 json jersey

我一直在谷歌搜索我的屁股试图找到如何做到这一点:我有一个泽西REST服务.调用REST服务的请求包含JSON对象.我的问题是,从Jersey POST方法实现,我如何才能访问HTTP请求正文中的JSON?

任何提示,技巧,示例代码的指针将不胜感激.

谢谢...

--Steve

pes*_*lla 15

正如已经建议的那样,将@ConsumesContent-Type 更改为text/plain可行,但从REST API的角度来看似乎并不正确.

想象一下,您的客户必须将POST JSON发送到您的API,但需要将Content-Type标头指定为text/plain.在我看来,它并不干净.简单来说,如果您的API接受JSON,那么请求标头应该指定Content-Type: application/json.

为了接受JSON但将其序列化为String对象而不是POJO,您可以实现自定义MessageBodyReader.这样做同样容易,您不必在API规范上妥协.

值得阅读MessageBodyReader的文档,以便确切知道它是如何工作的.我就这样做了:

步骤1.实现自定义MessageBodyReader

@Provider
@Consumes("application/json")
public class CustomJsonReader<T> implements MessageBodyReader<T> {
  @Override
  public boolean isReadable(Class<?> type, Type genericType,
      Annotation[] annotations,MediaType mediaType) {
    return true;
  }

  @Override
  public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
      MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

    /* Copy the input stream to String. Do this however you like.
     * Here I use Commons IOUtils.
     */
    StringWriter writer = new StringWriter();
    IOUtils.copy(entityStream, writer, "UTF-8");
    String json = writer.toString();

    /* if the input stream is expected to be deserialized into a String,
     * then just cast it
     */
    if (String.class == genericType)
      return type.cast(json);

    /* Otherwise, deserialize the JSON into a POJO type.
     * You can use whatever JSON library you want, here's
     * a simply example using GSON.
     */
    return new Gson().fromJson(json, genericType);
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的基本概念是检查输入流是否应该转换为String(指定者Type genericType).如果是这样,那么只需将JSON转换为指定的type(将是a String).如果期望的类型是某种POJO,则使用JSON库(例如Jackson或GSON)将其反序列化为POJO.

步骤2.绑定MessageBodyReader

这取决于您使用的框架.我发现Guice和Jersey一起工作得很好.这是我在Guice中绑定MessageBodyReader的方法:

在我的JerseyServletModule中,我像这样绑定读者 -

bind(CustomJsonReader.class).in(Scopes.SINGLETON);
Run Code Online (Sandbox Code Playgroud)

上面CustomJsonReader将JSON有效负载反序列化为POJO,如果您只是想要原始JSON String对象.

这样做的好处是它会接受Content-Type: application/json.换句话说,您的请求处理程序可以设置为使用JSON,这似乎是正确的:

@POST
@Path("/stuff")
@Consumes("application/json") 
public void doStuff(String json) {
  /* do stuff with the json string */
  return;
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*raf 13

Jersey支持使用Jettison类型JSONObject和JSONArray对解析的JSONObject进行低级访问.

<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.8</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

例如:

{
  "A": "a value",
  "B": "another value"
}


@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON) 
public void doStuff(JSONObject json) {
  /* extract data values using DOM-like API */
  String a = json.optString("A");
  Strong b = json.optString("B");
  return;
}
Run Code Online (Sandbox Code Playgroud)

有关更多示例,请参阅Jersey文档.

  • 这对我不起作用.我得到......`无法识别的字段"A"(类org.json.JSONObject),未标记为可忽略的`...如果我添加以下内容...`mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);` ......然后对象来自空的`{}` (4认同)

And*_*ndy 12

我不确定你如何获得JSON字符串本身,但你当然可以获得它包含的数据,如下所示:

定义一个JAXB带注释的Java类(C),它具有与在请求中传递的JSON对象相同的结构.

例如,对于JSON消息:

{
  "A": "a value",
  "B": "another value"
}
Run Code Online (Sandbox Code Playgroud)

使用类似的东西:

@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
  public String A;
  public String B;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用类型C的参数在资源类中定义方法.当Jersey调用您的方法时,将基于POSTed JSON对象创建JAXB对象.

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上事实证明它比我想象的要简单得多.我可以将HTTP请求的主体作为字符串参数获取,然后使用任何JSON库(当前使用Google GSON)处理它以将请求数据转换为本地对象. (4认同)
  • 不幸的是,JSON字符串基本上更多地用作字典而不是真正的POJO.我宁愿不必为JSON对象创建一个新的POJO. (2认同)

Wil*_*ill 7

这使您可以访问原始帖子.

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}
Run Code Online (Sandbox Code Playgroud)