web-dev-qa-db-ja.com

シリアライゼーションのためにジャージーのJSON / JAXBを再利用する方法は?

Jerseyを使用して実装されたJAX-RS RESTサービスがあります。 JAX-RS/Jerseyの優れた機能の1つは、いくつかのRESTアノテーションを散布するだけでPOJOをJavaサービスに簡単に変換できることです... POJOを変換するための簡単なメカニズムを含むJSONへ-JAXBアノテーションを使用。

ここで、REST以外の目的でこのクールなJSON化機能を利用できるようにしたいと思います。これらのオブジェクトの一部をJSONテキストとしてディスクにシリアル化できるようになりたいです。以下は、シリアライズしたいJAXBオブジェクトの例です。

@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {

    public UserInfoImpl() {} 

    public UserInfoImpl(String user, String details) {
        this.user = user;
        this.details = details;
    }

    public String getUser() { return user; }
    public void setUser(String user) { this.user = user; }

    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }

    private String user;
    private String details;
}

ジャージーはこれらの1つを追加情報なしでjsonに変換できます。ジャージーが私のようなニーズのためにAPIでこの機能を公開しているかどうか疑問に思いますか?私は今のところそれを見つけることができません...

ありがとう!

PDATE 2009-07-09:私は、Providersオブジェクトを使用してほとんど自分のやりたいことを正確に実行できることを学びました:

  @Context Providers ps;
  MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

  uw.writeTo(....)

...これは、jsonとしてオブジェクトを任意の出力ストリームに書き込みます。これは私にとって完璧ですが、@ Componentオブジェクトから@Contextを使用して、Providersオブジェクトでのみ取得できます。通常のアノテーションなしのPOJOからアクセスする方法を知っている人はいますか?ありがとう!

28
ctwomey

Jerseyは、maped()、badgerfish()、またはnatural()表記のどちらを使用するかに応じて、いくつかの異なるフレームワークを使用します。自然は通常、人々が望むものです。そしてそれは、Object-> JAXB-> JSONに由来する非常に優れた(そして非常に高速な)スタンドアロンのJackson JSONプロセッサーを使用して実装されています。ただし、Jacksonは、Object-> JSONに直接アクセスするための独自のJAX-RSプロバイダーも提供しています。

実際、彼らはJAXBアノテーションのサポートさえ追加しました。見て

http://wiki.fasterxml.com/JacksonJAXBAnnotations

それが最終的にあなたが探しているものだと思います。ジャクソンはObject <-> JSON処理を行います...ジャージーはあなたのために呼び出しを行います

19
Andy O

次に、JAXBを使用してオブジェクトをJSONにマップする簡単な簡単な例を示します(Jacksonを使用)。

http://ondra.zizka.cz/stranky/programovani/Java/jaxb-json-jackson-howto.texy

6
Ondra Žižka
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
5
RimasK

JAXBアノテーションは、XMLへのシリアル化時に正常に機能します。主な問題は、JAXBが空の配列をサポートしないことです。したがって、このようなものをシリアル化すると...

List myArray = new ArrayList();

... jaxbアノテーションを介してjsonに送信すると、すべての空の配列が[]ではなくnullになります。

これを解決するには、ジャクソンを介してjjoに直接pojoをシリアル化します。

Jerseyのユーザーガイドからこれを見てください: http://jersey.Java.net/nonav/documentation/latest/user-guide.html#d0e1959

これは、JAXBなしでJacksonプロバイダーを使用する最良の方法です。さらに、ウェブからjackson-all-x.y.z-jarをダウンロードすることにより、常に最新バージョンのジャクソンを使用できます。

この方法はあなたのjaxbアノテーションに干渉しないので、試してみることをお勧めします!

3
ramon_salla

ジャージー固有の小さなブートストラップを使用すると、それを使用して必要なJSONオブジェクトを作成できます。次の依存関係を含める必要があります(バンドルを使用できますが、テストにWeldを使用している場合は問題が発生します)。

    <dependency>
        <groupId>com.Sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.12</version>
    </dependency>
    <dependency>
        <groupId>com.Sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.12</version>
    </dependency>

そこから、JAXB注釈付きクラスを作成できます。次に例を示します。

@XmlRootElement
public class TextMessage {
private String text;
    public String getText() { return text; }
    public void setText(String s) { this.text = text; }
}

次に、次の単体テストを作成できます。

    TextMessage textMessage = new TextMessage();
    textMessage.setText("hello");
    textMessage.setUuid(UUID.randomUUID());

    // Jersey specific start
    final Providers ps = new Client().getProviders();
    // Jersey specific end
    final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {

        @Override
        public void add(final String key, final Object value) {
        }

        @Override
        public void clear() {
        }

        @Override
        public boolean containsKey(final Object key) {
            return false;
        }

        @Override
        public boolean containsValue(final Object value) {
            return false;
        }

        @Override
        public Set<Java.util.Map.Entry<String, List<Object>>> entrySet() {
            return null;
        }

        @Override
        public List<Object> get(final Object key) {
            return null;
        }

        @Override
        public Object getFirst(final String key) {
            return null;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Set<String> keySet() {
            return null;
        }

        @Override
        public List<Object> put(final String key, final List<Object> value) {
            return null;
        }

        @Override
        public void putAll(
                final Map<? extends String, ? extends List<Object>> m) {
        }

        @Override
        public void putSingle(final String key, final Object value) {
        }

        @Override
        public List<Object> remove(final Object key) {
            return null;
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public Collection<List<Object>> values() {
            return null;
        }
    };

    final MessageBodyWriter<TextMessage> messageBodyWriter = ps
            .getMessageBodyWriter(TextMessage.class, TextMessage.class,
                    new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Assert.assertNotNull(messageBodyWriter);

    messageBodyWriter.writeTo(textMessage, TextMessage.class,
            TextMessage.class, new Annotation[0],
            MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
    final String jsonString = new String(baos.toByteArray());
    Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));

このアプローチの利点は、JEE6 API内にすべてが保持されることです。プロバイダーのテストと取得以外には、明示的に外部ライブラリは必要ありません。ただし、標準では何も提供されておらず、実際には使用しないため、MultivaluedMapの実装を作成する必要があります。 mayもGSONより遅く、必要以上に複雑です。

1

JerseyはJAX-RSのリファレンス実装であり、JAX-RSはRESTサービスのエンドポイントを実装する標準的な方法を提供することに完全に集中しているため、ペイロードのシリアル化の問題は他の標準。

JAX-RS標準にオブジェクトのシリアライゼーションが含まれていると、実装が難しく、フォーカスの一部が失われる大きなマルチヘッドの獣になると思います。

RESTエンドポイントを提供することにジャージーがどれほど重点を置いているかに感謝します。私の場合、すべてのJAXBプラムが含まれる親をサブクラス化して、バイナリとXMLの間でオブジェクトをマーシャリングしましたとてもきれいです。

1
Jack Cox

私はXMLビューを理解していますが、POJOのJSONサポートを標準装備として要求することにはある程度の先見性があったでしょう。実装がJSONでクライアントがJavaScript RIAの場合、JSON識別子を特殊文字で修正する必要はありません。

また、Java BeanはPOJOではありません。Web層の外面で次のようなものを使用したいと思います。

public class Model
{
   @Property height;
   @Property weight;
   @Property age;
}

デフォルトのコンストラクターはなく、getter/setterノイズはありません。自分の注釈を付けたPOJOだけです。

0
rickoshay