今更感がありますが、SAStrutsでJSONを処理できるようにしてみました。
JSONリクエスト
SAStrutsはS2RequestProcessor.java
でHTTPリクエストをアクションフォームにコピーしているので、JSONリクエストの処理はその直前で行います。
JSONデータの読み込みはJacksonを使いました。
package sample.sastruts.json.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.seasar.framework.beans.util.Beans;
import org.seasar.framework.util.ReaderUtil;
import org.seasar.struts.action.S2RequestProcessor;
import org.seasar.struts.util.S2ActionMappingUtil;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class S2JSONRequestProcessor extends S2RequestProcessor {
@Override
protected void processPopulate(HttpServletRequest request,
HttpServletResponse response, ActionForm form, ActionMapping mapping)
throws ServletException {
if (form == null) {
return;
}
String contentType = request.getContentType();
String method = request.getMethod();
if (contentType != null && contentType.startsWith("application/json")
&& "POST".equalsIgnoreCase(method)) {
form.setServlet(servlet);
form.setMultipartRequestHandler(null);
processExecuteConfig(request, response, mapping);
form.reset(mapping, request);
Object actionForm = S2ActionMappingUtil.getActionMapping()
.getActionForm();
try {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
String postBody = ReaderUtil.readText(request.getReader());
Object value = mapper.readValue(postBody, actionForm.getClass());
Beans.copy(value, actionForm).execute();
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new ServletException(e.getMessage(), e);
}
} else {
super.processPopulate(request, response, form, mapping);
}
}
}
一番キモとなっているのは以下の部分です。
JSONリクエストをactionForm.getClass()
型としてvalue
に読み込んでいるので、actionForm
に値をコピーできます。
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
String postBody = ReaderUtil.readText(request.getReader());
Object value = mapper.readValue(postBody, actionForm.getClass());
Beans.copy(value, actionForm).execute();
このクラスをstruts-config.xml
のprocessorClass
に設定すると利用できます。
<controller
maxFileSize="1024K"
bufferSize="1024"
processorClass="sample.sastruts.json.action.S2JSONRequestProcessor"
multipartClass="org.seasar.struts.upload.S2MultipartRequestHandler"/>
JSONレスポンス
SAStrutsのアクションは遷移先のパスを戻り値に書いてJSP等と連携しますがnull
を返却すると遷移しません。これを利用しつつアクションからHTTPレスポンスに直接JSONを書き出します。
JavaオブジェクトからJSONの変換もJacksonを使っています。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;
public class XXXAction {
@Execute(validator = false)
public String xxx() throws JsonProcessingException {
String[] result = {"foo", "bar"};
ObjectMapper mapper = new ObjectMapper();
ResponseUtil.write(mapper.writeValueAsString(result), "application/json", "UTF-8");
return null;
}
}
追記
スマートなJSONレスポンスの実装方法の解説がありましたので、そちらもご覧下さい。
SAStrutsでJSON形式のデータを返す(検証エラー込み)
JSONサンプルアプリ
SAStrutsの足し算チュートリアルでJSONを利用するように修正したサンプルアプリを作りました。
こちらでは更にBean Validationをバリデータに利用しています。