DEV Community

KOGA Mitsuhiro
KOGA Mitsuhiro

Posted on • Originally published at qiita.com

SAStrutsとJSON

今更感がありますが、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.xmlprocessorClassに設定すると利用できます。

<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をバリデータに利用しています。

https://bitbucket.org/shiena/sample-sastruts-json-webapps

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay