SpringMVCの@RequestBodyの@ValidでJSONをバリデートする

昨日から引き続きやってるの表題の件ですが、
とりあえず定義したvalidatorを使って欲しい感じのエラーコードを
受け取れるところまでは出来ました。
 
– Controller

@ExceptionHandler
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleMethodArgumentNotValidException(
		MethodArgumentNotValidException error) {
	logger.info("JSON Validate: " + error.getMessage());

– servlet-context.xml

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
		<list>
			<ref bean="jsonConverter" />
		</list>
	</property>
	<property name="webBindingInitializer">
  		<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
	        <property name="validator">
				<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
			</property>
  		</bean>
	</property>
</bean>

上記のように設定することで以下のようなエラーメッセージが取れてきます。

INFO : com.shinodogg.hoge.HomeController - JSON Validate:
Validation failed for argument at index 0 in method:
public java.lang.String com.shinodogg.hoge.HomeController.hogeJsonPost(com.shinodogg.hoge.Hoge,java.util.Locale,org.springframework.ui.Model), with 1 error(s):
[Field error in object 'hoge' on field 'id': rejected value [123];
codes [Max.hoge.id,Max.id,Max.java.lang.Integer,Max];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [hoge.id,id]; arguments []; default message [id],100]; default message [must be less than or equal to 100]]

ってことで、こいつをホゲホゲしてやれば、Formの時に↓こんな風にして取得する

if (result.hasErrors()) {
	List errorList = result.getAllErrors();
	for (ObjectError error : errorList) {
		logger.info(error.getDefaultMessage());
		for (int i = 0; i < error.getCodes().length; i++ ) {
			logger.info(error.getCodes()[i]);
		}

↓のエラーコードと合わせて共通化出来そうな予感です。

INFO : com.shinodogg.hoge.HomeController - Max.hoge.id
INFO : com.shinodogg.hoge.HomeController - Max.id
INFO : com.shinodogg.hoge.HomeController - Max.java.lang.Integer
INFO : com.shinodogg.hoge.HomeController - Max

 
 
但し、JSONの場合、Integer型の項目に文字列を突っ込んでやると、、、
MethodArgumentNotValidExceptionではなく、HttpMessageNotReadableExceptionが返ってきちゃう件は、
解決できませんでした。
 
事象としては、
– Formのバリデーションの時は↓だったけど、

INFO : com.shinodogg.hoge.HomeController - typeMismatch.hoge.id
INFO : com.shinodogg.hoge.HomeController - typeMismatch.id
INFO : com.shinodogg.hoge.HomeController - typeMismatch.java.lang.Integer
INFO : com.shinodogg.hoge.HomeController - typeMismatch

– JSONの場合は↓のようなHttpMessageNotReadableExceptionが出てしまうといった感じ。

org.springframework.http.converter.HttpMessageNotReadableException:
Could not read JSON: Can not construct instance of java.lang.Integer from String value 'aa':
not a valid Integer value
 at [Source: org.apache.catalina.connector.CoyoteInputStream@1f82d1be; line: 1, column: 2] (through reference chain: com.shinodogg.hoge.Hoge["id"]);
nested exception is org.codehaus.jackson.map.JsonMappingException:
Can not construct instance of java.lang.Integer from String value 'aa': not a valid Integer value
 at [Source: org.apache.catalina.connector.CoyoteInputStream@1f82d1be; line: 1, column: 2] (through reference chain: com.shinodogg.hoge.Hoge["id"])

 
コレに関しては↓のJIRA上での議論みると、
Spring MVC Binding Lifecycle differs between @RequestBody arguments and plain JavaBean arguments
↓って書いてあります。

We don't support a BindingResult argument after @RequestBody indeed.
I think handling HttpMessageNotReadableException or RequestBodyNotValidException centrally
from an exception resolver should be adequate.
If there are good use cases we can consider it of course.

まぁ経緯まではアレですが、自分でExceptionの中身みてハンドリングしろやって事のようです。
どのカラムについてIntegerにStringを突っ込めねーよってのはメッセージに記載されているので、
ちょっとホゲホゲすりゃイイかって感じで。
 
この件についてイカしたソリューションお持ちの方は是非@shinodoggまでDMとかmention
飛ばしていただけるとありがたいですmm
 

あんまり本題と関係ないですが beans:beanって書くのがかったるくなったので、
servlet-context.xmlの名前空間の宣言変えました。
 
SpringMVCプロジェクト作ると↓のようになっていると思いますが、

xmlns="http://www.springframework.org/schema/mvc"
xmlns:beans="http://www.springframework.org/schema/beans"

↓に変えてやります。

xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"

↓ら辺にmvc:ってつけなきゃいけなくなりますが、beans:を多発するよりスッキリかな、と。

<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />

 

Webアプリケーション設計・実装のためのフレームワーク活用の技術
古川 正寿 早川 順
翔泳社
売り上げランキング: 207543

コメント

タイトルとURLをコピーしました