5

次のような JAX-RS 1 環境 (RestEasy 2 と Jackson プロバイダー) にデータ クラスがあるとします。

class Foo {
   int id;
   String name;
   Bar bar;

   ...
}

Barある:

class Bar {
   int one;
   String two;
}

今、私は特別な方法で連載したいと思っていますBar(おそらく、要求されたメディアの種類に応じて (または月の満ち欠けに応じて)、私はMessageBodyWriter<Bar>

@Provider
@Produces("application/json")
public class BarWriter implements MessageBodyWriter<Bar> {
   ...
}

Barのように単独で要求された場合、非常にうまく機能します

@GET @Path("bar")  
public Bar getBar() { return new Bar(...); }

しかし、私Foo

@GET @Path("foo")  
public Foo getFoo() { return new Foo(...); }

メッセージ本文ライターは無視されます。

今私が欲しいのは、これMessageBodyWriterが私が戻ったときFoo、またはList<Bar>

MessageBodyWriter後者はケースのカスタムを書くだけで実現できると思いますが、List前者の場合、Barフィールドを含むすべてのアプリケーション クラスに対してメッセージ ボディ ライターを書くことはできません。

これを解決する方法についてのアイデアはありますか? インスタンスでJacksonシリアライザーも使用しようとしていましBarたが、これはRestEasyによって登録されていないようです(とにかく、その方法は壊れやすいと思います)。

4

3 に答える 3

6

残念ながら、これはメッセージ本文ライターの仕組みではありません。JAX-RS 実装は、リソース メソッドから返されるタイプに基づいて、シリアライゼーションで使用されるライターを見つけます。したがって、あなたの場合、 に対して定義されたカスタム ライターを使用してBar、このリソース メソッドを使用します。

@GET @Path("bar")  
public Bar getBar() { return new Bar(...); }

JAX-RS プロバイダーはBar、カスタム ライターを使用してシリアル化します。ただし、このリソース メソッドの場合:

@GET @Path("foo")  
public Foo getFoo() { return new Foo(...); }

カスタム ライターが定義されておらず、シリアル化は、戻りクラスとコンテンツ タイプの組み合わせを処理できる、最初に一致した (既定の) プロバイダーによって処理されます。覚えておくべき重要なことは、一般的な JSON および XML シリアライゼーション ライブラリとは異なり、JAX-RS エンティティ プロバイダーは再帰的ではないということです。つまり、リソース メソッドで返される特定のオブジェクトの場合、プロバイダーは、変数として含まれる型ではなく、 に対してのみカスタムAライターを見つけようとします。AA

Barただし、Jackson を使用しているので、クラスのカスタム シリアライザーを定義しないのはなぜですか? それはあなたが説明したほとんどすべてのシナリオを処理します:

public class BarSerializer extends JsonSerializer<Bar> {

    @Override
    public void serialize(final Bar value, final JsonGenerator jgen,
            final SerializerProvider provider) throws IOException,
            JsonProcessingException {

        jgen.writeStartObject();
        jgen.writeFieldName("myBar");
        jgen.writeString(value.getTwo());
        jgen.writeEndObject();
    }
}

次のように、Jackson にこのカスタム シリアライザーを使用するように指示します。

@JsonSerialize(using=BarSerializer.class)
class Bar {
   int one;
   String two;
}

最後に、シリアル化したときと同じ形式で JSON を取得することが予想される場合は、カスタム も必要になることを忘れないでくださいJsonDeserializer

それを機能させるには、クラスパスにjackson-mapperjackson-jaxrsjar が必要です (おそらく jarも必要ですjackson-core)。

于 2013-03-05T18:36:55.667 に答える
2

JAX-RS ランタイムはMessageBodyWriter、リソース メソッドによって返されたオブジェクトの 1 つだけを検索し (仕様のセクション「4.2.2 メッセージ ボディ ライター」を参照)、その単一MessageBodyWriterは、オブジェクト グラフ全体のシリアル化を完全に制御します。クライアントに返されました。

必要な動作を実装するには、MessageBodyWriterメディア タイプごとにカスタムが必要です。これは、オブジェクト グラフの一部のシリアル化を、グラフ内の特定のタイプに遭遇するたびに別のライターに委譲し、それから独自のライターを再開します。論理。特定のタイプのデリゲート ライターを取得することは大きな問題ではありませんが ( inject a javax.ws.rs.ext.Providersと call getMessageBodyWriter())、既存の xml/json/etc シリアライザーがそのような種類の拡張機能を念頭に置いて実装されているとは思わないので、それらを中継することはできませんでした。このためだけに xml マーシャラーを再実装することも魅力的なオプションではありません。

于 2013-03-05T18:36:43.220 に答える
-1

Java オブジェクトのシリアライゼーション用のカスタム メッセージ ボディ ライターの記述については、以下の投稿を参照してください。

http://h2labz.blogspot.in/2014/12/marshalling-java-to-json-in-jax-rs.html

于 2014-12-22T11:35:28.703 に答える