Spring WebMVCをやってみる (18) - AnnotationFormatterFactory -
前回でも書いたように、@DateTimeFormatのようなアノテーションによってFormatterが作用する仕組みっていうのを作る事も出来る。それを担うのがAnnotationFormatterFactoryになる模様
要件
前回のをそのまま利用するけどコントローラー側では@SampleFormatっていうアノテーションを利用することによりFormatterを作用させるようにする。でそのFormatter自体は前回とまったくそのまま
package sample;
import java.text.ParseException;
import java.util.Locale;
import org.springframework.format.Formatter;
public class SampleFormatter implements Formatter<Sample> {
@Override
public String print(Sample object, Locale locale) {
return object.getName().toLowerCase();
}
@Override
public Sample parse(String text, Locale locale) throws ParseException {
return Sample.valueOf(text.toUpperCase());
}
}
を使う
SampleFormat.java
引数実装とかもやっておけばAnnotationFormatterFactoryを通じてFormatterに渡す事も可能だと思うのだけど今回はパス
package sample;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface SampleFormat {
}
まぁ見て分かるようにアノテーションのインターフェースなだけ
SampleFormmaterFactory.java
package sample;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
public class SampleFormatterFactory implements AnnotationFormatterFactory<SampleFormat> {
@Override
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(Arrays.asList(Sample.class));
}
@Override
public Printer<?> getPrinter(SampleFormat annotation, Class<?> fieldType) {
return new SampleFormatter();
}
@Override
public Parser<?> getParser(SampleFormat annotation, Class<?> fieldType) {
return new SampleFormatter();
}
}
Formatterはorg.springframework.format.Parser自体を継承しているインターフェースなので、そのままインスタンス作ってぶん投げれば良い
spring-web-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="sample" />
<mvc:annotation-driven conversion-service="conversionService" />
<bean
id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="sample.SampleFormatterFactory" />
</set>
</property>
</bean>
</beans>
まぁ前回同様にformattersにAnnotationFormatterFactoryの実装クラスを指定してやりゃいい模様で
SampleController.java
package sample;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/sample")
public class SampleController {
@RequestMapping("/test")
public void test(@RequestParam("name") @SampleFormat Sample sample, ModelMap model) {
model.addAttribute("sample", sample);
}
}
っていう感じで利用できる。
ただ不明な所として1点上げると、「getPrinter実装してもどういう作用で発生するのかが謎」。普通にFormatterを使う場合とかだと<spring:bind expression="" />等で作用されるっていうはあるのだけど、このAnnotationFormatterFactoryの事象だけはgetPrinterメソッドが作用する事が無い。ここがよう分からんっていうところかなと
んまぁFormatterに関するネタはこれで終わり(なはず)なんだけど、疑問点として「フォームコンポーネントにフォーマット化した文字列を処理させたい場合はどうなのか」っていう点。<form:input>とか使ってもFormatter#printが作用してくれないので
<input type="text" value="<spring:eval expression="省略" />" />
みたいに書かないとダメなのかっていう点。そこも微妙なのでわかり次第書く予定
余談: FormatterRegistrarを使う場合
package sample;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;
public class SampleFormatterRegistrar implements FormatterRegistrar {
@Override
public void registerFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new SampleFormatterFactory());
}
}
みたいにやれば良いっぽい