Stripes Frameworkどうよ。その6〜JSONリクエストのバインド

今どきは、Play frameworkやNode.js、Java EE6、Jerseyあたりを追うべきなのかもしれませんが、自分はStripes Frameworkいじってます。

JSONリクエストをActionBeanにバインドできるように拡張してみます。Jacksonを使います。

ActionBeanにリクエストマッピングするActionBeanPropertyBinder、エクセプションを処理するExceptionHandlerの実装を置き換えます。まず、web.xmlの設定

<filter>
  <display-name>Stripes Filter</display-name>
  <filter-name>StripesFilter</filter-name>
  <filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class>

  :
  :

  <init-param>
    <param-name>ActionBeanPropertyBinder.Class</param-name>
    <param-value>selva.XActionBeanPropertyBinder</param-value>
  </init-param>
  <init-param>
    <param-name>ExceptionHandler.Class</param-name>
    <param-value>selva.XExceptionHandler</param-value>
  </init-param>

  :
  :

</filter>

で、JSONリクエストをバインドクラス、XActionBeanPropertyBinderは、以下の感じ。Content-Typeがapplication/jsonならば、処理する。

package selva;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.controller.DefaultActionBeanPropertyBinder;
import net.sourceforge.stripes.validation.ValidationErrors;

import org.codehaus.jackson.map.ObjectMapper;
import org.seasar.util.beans.util.BeanUtil;

public class XActionBeanPropertyBinder extends DefaultActionBeanPropertyBinder {

    @Override
    public ValidationErrors bind(ActionBean bean, ActionBeanContext context,
            boolean validate) {
        HttpServletRequest request = context.getRequest();
        String contentType = request.getHeader("Content-Type");
        if (!StringUtil.isBlank(contentType)
                && contentType.startsWith("application/json")) {
            try {
                ActionBean b = new ObjectMapper().readValue(
                        request.getInputStream(), bean.getClass());
                BeanUtil.copyBeanToBean(b, bean);
            } catch (Exception e) {
                throw new BadJsonRequestException(e);
            }
            return context.getValidationErrors();
        }
        return super.bind(bean, context, validate);
    }
}

で、バインドエラー時は、bad requestで返すクラス。

package selva;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.exception.DefaultExceptionHandler;

public class XExceptionHandler extends DefaultExceptionHandler {

    @Override
    public void init(Configuration configuration) throws Exception {
        super.init(configuration);
    }

    @Override
    public void handle(Throwable throwable, HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        if (throwable instanceof BadJsonRequestException) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    throwable.getMessage());
            return;
        }
        super.handle(throwable, request, response);
    }

}

以上