web-dev-qa-db-ja.com

JerseyサービスでJSONオブジェクトを使用する

私はこれを行う方法を見つけようとしてお尻をグーグルで探しています:私はジャージーRESTサービスを持っています。RESTサービスを呼び出すリクエストJSONオブジェクト。私の質問は、Jersey POSTメソッド実装から、HTTPリクエストの本文にあるJSONにアクセスするにはどうすればよいですか?

サンプルコードへのヒント、トリック、ポインターは大歓迎です。

ありがとう...

-スティーブ

33
Steve

JSON文字列自体を取得する方法がわかりませんが、次のように含まれているデータを取得できます。

リクエストで渡されるJSONオブジェクトと同じ構造を持つJAXBアノテーション付きJavaクラス(C)を定義します。

例えばJSONメッセージの場合:

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

次のようなものを使用します。

@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
  public String A;
  public String B;
}

次に、タイプCのパラメーターを使用してリソースクラスでメソッドを定義できます。Jerseyがメソッドを呼び出すと、POSTされたJSONオブジェクトに基づいてJAXBオブジェクトが作成されます。

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}
12
Andy

既に提案したように、_@Consumes_ Content-Typeを_text/plain_に変更しても機能しますが、REST APIの観点からは正しくないようです。

顧客がAPIに対してPOST JSONを使用する必要があるが、Content-Typeヘッダーを_text/plain_として指定する必要があることを想像してください。私の意見では、きれいではありません。 JSONの場合、リクエストヘッダーは_Content-Type: application/json_を指定する必要があります。

JSONを受け入れるが、POJOではなくStringオブジェクトにシリアル化するために、カスタム 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);
  }
}_

上記の基本的な概念は、入力ストリームがString(_Type genericType_で指定される)に変換されると予想されるかどうかをチェックすることです。その場合、指定されたtype(これはStringになります)にJSONをキャストするだけです。予想されるタイプが何らかのPOJOである場合、JSONライブラリ(例:JacksonまたはGSON)を使用して、それをPOJOにデシリアライズします。

ステップ2. MessageBodyReaderをバインドします

これは、使用しているフレームワークによって異なります。 GuiceとJerseyがうまく機能していることがわかります。 Guiceで MessageBodyReader をバインドする方法は次のとおりです。

私の JerseyServletModule のようにリーダーをバインドします-

bind(CustomJsonReader.class).in(Scopes.SINGLETON);

上記の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;
}_
15
pestrella

Jerseyは、JettisonタイプのJSONObjectおよびJSONArrayを使用して、解析されたJSONObjectへの低レベルのアクセスをサポートします。

<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.8</version>
</dependency>

例えば:

{
  "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;
}

その他の例については、 Jersey documentation を参照してください。

13
Peter Centgraf

これにより、未加工の投稿にアクセスできます。

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}
7
Will

JSONを値として持つパラメーターを使用して、form/HTTP.POSTを送信/ POSTします。

@QueryParam jsonString

public desolveJson(jsonString)

0
doyle