JAX-RSで好きなオブジェクトを返す

今回は使用頻度が高いJAX-RSの機能を解説。

JAX-RSではデフォルトである程度の変換機能はあるが、これを自由に、そして簡単にカスタマイズできる。

今回はjava.util.Propertiesを返すようにしてみよう。

リソース定義。

package jaxrs;

import java.util.Properties;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

@Path("hoge")
public class Hoge {

    @GET
    @Produces("text/plain; charset=UTF-8")
    @Consumes
    public Properties getProps() {

        Properties props = new Properties();
        props.setProperty("KEY", "VALUE");
        props.setProperty("HOGE", "ほげ?");
        props.setProperty("ぷろぱてぃ", "めっせーじ");

        return props;
    }
}


このままだとPropetiesをどう変換したらよいかわからないのでそれを教えてあげる。MessageBodyWriterを実装したクラスを作るとよい。

package jaxrs;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Properties;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

@Provider
public class PropertyWriter implements MessageBodyWriter<Properties>{

    public boolean isWriteable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return type.equals( Properties.class );
    }

    public long getSize(Properties t, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    public void writeTo(Properties t, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
            throws IOException, WebApplicationException {

        Writer writer = new OutputStreamWriter(entityStream,"UTF-8");
        t.store(writer, null);
        
    }
}

ポイントは@Provider。これがあるとこいつはJAX-RSでの設定用ファイルだとみなされて、自動で登録される。

isWriteableメソッドがこのMessageBodyWriterの対象になるかどうかのboolean。writeToがストリームで出力する。


実行!
http://shin.cside.com/diary/2010/0921-01.png



Entityの入力のときにももちろん利用可能。その場合はMessageBodyReaderを利用する。


あらゆるクラスを簡単に拡張できるのがわかっただろうか。Imageを戻り値に記述して"image/png"で出力する等も簡単にできるということ。引数を見るとわかるが、mimeも柔軟に対応できる。


おそらくJAX-RSを設計するに当たり、最も活躍するのがこのMessageBodyWriter/Reader。事実上のフィルタとして動作するため、開発者は単純にDTO用のBean等にアノテーションを目印としてつけてるだけで、自動で変換やヘッダ挿入も可能だ。

以下のようにwriteToに記述するとレスポンスヘッダに追加される。

        httpHeaders.add("responseid", "hogehoge0001");

http://shin.cside.com/diary/2010/0921-02.png


ヘッダを利用してコントロールするということはよくあると思うので覚えておきたい。