Hatena::Groupprogram

ひとり開発日記。 このページをアンテナに追加 RSSフィード

2014/04/07 (Mon)

Resteasy 3.0.6.Finalで、JSONのレンダリングエンジンにGSONを使う。

| Resteasy 3.0.6.Finalで、JSONのレンダリングエンジンにGSONを使う。 - ひとり開発日記。 を含むブックマーク はてなブックマーク - Resteasy 3.0.6.Finalで、JSONのレンダリングエンジンにGSONを使う。 - ひとり開発日記。

JAX-RSJSONを返すプログラムを作ろうとして、慣れているResteasy+Guiceで作ろうかな、って思っていて。

Resteasyは、基本的に、Jacksonを使ってJSONレンダリングを行うんですよね。自分も、基本的には、既存のベーシックなモジュールを活用した方が良いと思うんですが、Jackson連携モジュールMavenで入れたら、ものすごくいっぱい依存ライブラリ入るんです。 エンティティをJSONレンダリングするだけなのにねぇ。 後、下記二つのことがやりたかったのですが、Jackson連携モジュール経由だと、どうやるのかよく分からなかったと言う。

  1. (所謂)"pritty-print"なJSON出力
  2. キャメルケースなエンティティのフィールドを、JSON出力時はスネイクケースに

これなら、GSON使った方が早いかな、って思って、やってみたら、記述は少なかったんですが、以外と難しかったですね…。

まず、GuiceのDI用のモジュールクラス内で、GSONのインスタンス作って、DI設定。 JSONのフォーマットはGsonBuilderで設定。 Javadocに割と分かり易く書かれてますね。

public class ConfigModule extends AbstractModule {

	@Override
	protected void configure() {
		// JSON
		Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG)
				.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
				.setPrettyPrinting()
				.setVersion(1.0)
				.create();
		bind(Gson.class).toInstance(gson);
		bind(JsonMessageProvider.class);

		// 以下省略
	}
}

次に、MessageBodyWriterの実装を書いて、これもDIしておく、と。

/** application/jsonのフォーム内容を書き出すProvider実装クラス */
@Provider
@Singleton
@Produces(MediaType.APPLICATION_JSON)
public class JsonMessageProvider implements MessageBodyWriter<Object> {

	@Inject
	protected Gson gson;

	@Override
	public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
		return true;
	}

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

	@Override
	public void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
			MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
			WebApplicationException {
		try (OutputStreamWriter writer = new OutputStreamWriter(entityStream, Charsets.UTF_8)) {
			Type jsonType = type.equals(genericType) ? type : genericType;
			gson.toJson(t, jsonType, writer);
		}
	}
}

writeToメソッドの中で、Typeクラスをごにょごにょしてるのは、GSONのジェネリクスの扱いの回避のためです*1

これで、 MediaType.APPLICATION_JSON な出力の際は、 JsonMessageProvider を経て、GSONでJSONレンダリングされるようになりましたよ、と。*2

トラックバック - http://program.g.hatena.ne.jp/halflite/20140407