12. Spring Frameworkとの連携
DI(Depenency Injection) 機能のフレームワーク Spring Framework と連携することができます。
Spring Framework のコンテナで管理可能、DI可能な部分は、次の箇所になります。
これらの機能・箇所は、 BeanFactory
によるインスタンスを新しく作成する箇所であり、その実装を SpringBeanFactory
に切り替え得ることで、DIを実現します。
機能・箇所 |
説明 |
---|---|
|
|
|
|
|
|
|
|
リスナクラスがSpringBeanとして管理可能です。 |
|
|
|
BeanValidation の検証用の実装クラスがSpringBeanとして管理可能です。 |
|
|
12.1. ライブラリの追加
Spring Frameworkを利用する際には、ライブリを追加します。 Mavenを利用している場合は、pom.xmlに以下を追加します。
Spring Frameworkのバージョンは、3.0以上を指定してください。
1<dependency>
2 <groupId>org.springframework</groupId>
3 <artifactId>spring-context</artifactId>
4 <version>4.3.2.RELEASE</version>
5</dependency>
12.2. SpringBeanFactoryの設定方法
12.2.1. XMLによるコンテナの設定
XMLによる設定方法を説明します。
コンテナの定義の基本は次のようになります。
アノテーションによるDIの有効化を行います。
コンポーネントスキャン対象のパッケージの指定を行います。
com.github.mygreen.supercsv.builder.SpringBeanFactory
をSpringBeanとして登録します。
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- XMLによるコンテナの定義 -->
3<beans xmlns="http://www.springframework.org/schema/beans"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xmlns:context="http://www.springframework.org/schema/context"
6 xsi:schemaLocation="http://www.springframework.org/schema/beans
7 http://www.springframework.org/schema/beans/spring-beans.xsd
8 http://www.springframework.org/schema/context
9 http://www.springframework.org/schema/context/spring-context.xsd
10 ">
11
12 <!-- アノテーションによるDIの有効化の定義 -->
13 <context:annotation-config />
14
15 <!-- コンポーネントスキャン対象のパッケージの指定 -->
16 <context:component-scan base-package="sample.spring" />
17
18 <!-- Springのコンテナを経由するCSV用のBeanFactoryの定義 -->
19 <bean id="springBeanFactory" class="com.github.mygreen.supercsv.builder.SpringBeanFactory" />
20
21</beans>
12.2.2. JavaConfigによるコンテナの設定
Spring Framework3.0から追加された、JavaソースによるSpringBean定義の方法を説明します。
JavaConfigによる設定を使用する場合は、Spring Frameworkのバージョンをできるだけ最新のものを使用してください。 特に、機能が豊富なバージョン4.0以上の使用を推奨します。
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.ComponentScan;
3import org.springframework.context.annotation.Configuration;
4import org.springframework.context.annotation.Description;
5
6import com.github.mygreen.supercsv.builder.SpringBeanFactory;
7
8// Javaによるコンテナの定義
9@Configuration
10@ComponentScan(basePackages="sample.spring")
11public class SuperCsvConfig {
12
13 @Bean
14 @Description("Springのコンテナを経由するCSV用のBeanFactoryの定義")
15 public SpringBeanFactory springBeanFactory() {
16 return new SpringBeanFactory();
17 }
18
19}
12.2.3. SpringBeanとしての定義
ステレオタイプのアノテーション @Component/@Service/@Reposition/@Controller
をサポートしているため、
これらを使いSpringBeanを定義します。
12.2.3.1. 独自の書式の作成
独自の書式の TextFormatter
を定義する際には、スコープを proptotype にします。
読み込み時のエラーメッセージが、カラムごとに異なる場合があるため、インスタンスを別にします。
1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.context.annotation.Scope;
3import org.springframework.stereotype.Component;
4
5import com.github.mygreen.supercsv.cellprocessor.format.AbstractTextFormatter;
6import com.github.mygreen.supercsv.cellprocessor.format.TextParseException;
7
8
9/**
10 * {@link SampleType}に対するTextFromatterの実装
11 */
12@Scope("prototype")
13@Component
14public class SampleTypeFormatter extends AbstractTextFormatter<SampleType> {
15
16 // SpringBeanのインジェクション
17 @Autowired
18 private SampleService sampleService;
19
20 @Override
21 public SampleType parse(final String text) {
22
23 try {
24 // 業務ロジックなので省略
25 } catch(Exception e) {
26 throw new TextParseException(text, SampleType.class, e);
27 }
28
29 }
30
31 @Override
32 public String print(final SampleType object) {
33 // 業務ロジックなので省略
34 }
35
36}
12.2.3.2. 独自の変換/検証の作成
検証用の ConstraintProcessorFactory
の例として、DBにユーザが存在するかチェックするCellProcessorで説明します。
変換用の ConversionProcessorFactory
も同様の実装方法になります。
ConstraintProcessorFactory
はシングルトンで定義します。CellProcessorは、カラムごとに固有なインスタンスにするため、Springのコンテナ管理外とします。
CellProcessor内で、SpringBeanを利用したい場合は、 ConstraintProcessorFactory クラスでインジェクションしておき、 それをコンストラクタやsetterメソッドで渡すようにします。
1import java.util.Optional;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import org.springframework.stereotype.Component;
5import org.supercsv.cellprocessor.ift.CellProcessor;
6
7import com.github.mygreen.supercsv.builder.BuildType;
8import com.github.mygreen.supercsv.builder.Configuration;
9import com.github.mygreen.supercsv.builder.FieldAccessor;
10import com.github.mygreen.supercsv.cellprocessor.ConstraintProcessorFactory;
11import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
12
13/**
14 * ユーザ名がDBに存在するか検証するCellProcessorを作成するクラス
15 */
16@Component
17public class UserNameExistFactory implements ConstraintProcessorFactory<CsvUserNameExist> {
18
19 // SpringBeanのインジェクション
20 @Autowired
21 private UserService userService;
22
23 @Override
24 public Optional<CellProcessor> create(final CsvUserNameExist anno, final Optional<CellProcessor> next,
25 final FieldAccessor field, final TextFormatter<?> formatter, final Configuration config) {
26
27 // UserService はCellProcessorに渡す
28 final UserNameExist processor = next.map(n -> new UserNameExist(userService, n))
29 .orElseGet(() -> new UserNameExist(userService));
30 processor.setValidationMessage(anno.message());
31
32 return Optional.of(processor);
33 }
34
35}
CellProcessor は、コンストラクタで渡されたSpringBean(UserService)のメソッドを呼び出します。
1import org.supercsv.cellprocessor.ift.CellProcessor;
2import org.supercsv.cellprocessor.ift.StringCellProcessor;
3import org.supercsv.util.CsvContext;
4
5import com.github.mygreen.supercsv.cellprocessor.ValidationCellProcessor;
6
7/**
8 * ユーザ名の存在チェックを行う制約のCellProcessor
9 */
10public class UserNameExist extends ValidationCellProcessor implements StringCellProcessor {
11
12 private final UserService userService;
13
14 public UserNameExist(final UserService userService) {
15 checkPreconditions(userService);
16 this.userService = userService;
17 }
18
19 public UserNameExist(final UserService userService, final CellProcessor next) {
20 super(next);
21 checkPreconditions(userService);
22 this.userService = userService;
23 }
24
25 private static void checkPreconditions(final UserService userService) {
26 if(userService == null) {
27 throw new NullPointerException("userService should not be null");
28 }
29
30 }
31
32 @Override
33 public <T> T execute(final Object value, final CsvContext context) {
34
35 if(value == null) {
36 return next.execute(value, context);
37 }
38
39 final String result = value.toString();
40
41 // サービスのメソッドの呼び出し
42 if(!userService.existByUserName(result)) {
43 throw createValidationException(context)
44 .messageFormat("%s dose not found user name.", result)
45 .rejectedValue(result)
46 .build();
47 }
48
49 return next.execute(value, context);
50 }
51
52}
アノテーションの作成法補は、通常と変わりません。
メタアノテーション @CsvConstraint で ConstraintProcessorFactoryを実装したクラスUserNameExistFactoryを指定します。
1import java.lang.annotation.Documented;
2import java.lang.annotation.ElementType;
3import java.lang.annotation.Repeatable;
4import java.lang.annotation.Retention;
5import java.lang.annotation.RetentionPolicy;
6import java.lang.annotation.Target;
7
8/**
9 * ユーザが存在するかチェックするためのアノテーション
10 */
11@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
12@Retention(RetentionPolicy.RUNTIME)
13@Documented
14@Repeatable(CsvUserNameExist.List.class)
15@CsvConstraint(value=UserNameExistFactory.class)
16public @interface CsvUserNameExist {
17
18 String message() default "{sample.CsvUserNameExist.message}";
19
20 Class<?>[] groups() default {};
21
22 int order() default 0;
23
24 @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
25 @Retention(RetentionPolicy.RUNTIME)
26 @Documented
27 @interface List {
28
29 CsvUserNameExist[] value();
30 }
31
32}
12.2.3.3. 独自のProcessorBuilderクラスの作成
独自のクラスタイプのProcessorBuilderは、自身をSpringBeanとして登録します。 通常は、シングルトンでかまいません。
1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.stereotype.Component;
3
4import com.github.mygreen.supercsv.builder.AbstractProcessorBuilder;
5import com.github.mygreen.supercsv.builder.Configuration;
6import com.github.mygreen.supercsv.builder.FieldAccessor;
7import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
8
9@Component
10public class SampleTypeProcessorBuilder extends AbstractProcessorBuilder<SampleType> {
11
12 @Autowired
13 private SampleTypeFormatter formatter;
14
15 @Autowired
16 private SampleConstraintFactory sampleConstaintFactory;
17
18 @Override
19 protected void init() {
20 super.init();
21
22 // 制約や変換用のアノテーションの登録
23 // @CsvConstaint/@CsvCoversionの関連付けを省略し手いる場合に登録する
24 registerForConstraint(CsvSampleConstraint.class, sampleConstaintFactory);
25 }
26
27 @Override
28 protected TextFormatter<SampleType> getDefaultFormatter(final FieldAccessor field, final Configuration config) {
29 return formatter;
30 }
31
32}
12.2.3.4. CsvValidator の作成
CsvValidator クラスは、シングルトンで管理します。
SpringBeanをインジェクションしたいものがあれば行います。
1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.stereotype.Component;
3
4import com.github.mygreen.supercsv.validation.CsvBindingErrors;
5import com.github.mygreen.supercsv.validation.CsvValidator;
6import com.github.mygreen.supercsv.validation.ValidationContext;
7
8/**
9 * {@link UserCsv}に対するValidator
10 *
11 */
12@Component
13public class UserValidator implements CsvValidator<UserCsv> {
14
15 // SpringBeanのインジェクション
16 @Autowired
17 private UserService userService;
18
19 @Override
20 public void validate(final UserCsv record, final CsvBindingErrors bindingErrors,
21 final ValidationContext<UserCsv> validationContext) {
22
23 // 業務ロジックなので省略
24
25 }
26
27}
12.2.3.5. リスナクラスの作成
リスナクラスは、POJOであるため、SpringBeanをインジェクションしたいものがあれば行います。
1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.stereotype.Component;
3
4import com.github.mygreen.supercsv.annotation.CsvPostRead;
5import com.github.mygreen.supercsv.annotation.CsvPreWrite;
6
7/**
8 * {@link UserCsv}に対するリスナクラス
9 *
10 */
11@Component
12public class UserListener {
13
14 @Autowired
15 private UserService userSerivce;
16
17 @CsvPreWrite
18 @CsvPostRead
19 public void validate(final UserCsv record) {
20
21 // 業務ロジックなので省略
22
23 }
24
25}
12.2.4. CsvBeanの定義
CSVのBeanの定義では、SpringBeanとして定義したクラスを指定します。
1import com.github.mygreen.supercsv.annotation.CsvBean;
2import com.github.mygreen.supercsv.annotation.CsvColumn;
3import com.github.mygreen.supercsv.annotation.constraint.CsvRequire;
4import com.github.mygreen.supercsv.annotation.format.CsvFormat;
5import com.github.mygreen.supercsv.validation.beanvalidation.CsvBeanValidator;
6
7@CsvBean(header=true,
8 validator=UserValidator.class, // Spring管理のValidatorの指定
9 listener=UserListener.class // Spring管理のリスナクラスの指定
10)
11public class UserCsv {
12
13 // Srping管理のFormatterを指定する場合。
14 @CsvColumn(number=1, label="タイプ")
15 @CsvFormat(formatter=SampleTypeFormatter.class)
16 private SampleType sampleType1;
17
18 // Spring管理のConstraintProcessorFactory を利用している検証用アノテーション
19 @CsvColumn(number=2, label="名前")
20 @CsvUserNameExist
21 private String name;
22
23 // Spring管理のProcessorBuilderを指定する場合
24 @CsvColumn(number=3, label="ホームページ", builder=SampleTypeProcessorBuilder.class)
25 private SampleType sampleType2;
26
27 // setter/getterは省略
28
29}
注釈
SpringBeanの管理外のクラスを指定した場合は、通常の方法としてインスタンスが作成されます。
ただし、管理外のクラスでもインジェクション用のアノテーション(@Resource/@Autowired)があれば、 インジェクションされます。
12.2.5. SpringBeanFactoryの使用方法
BeanMappingFactory#getConfiguration()
取得できる、システム設定に、SpringBeanFactoryを設定します。
1import com.github.mygreen.supercsv.builder.BeanMapping;
2import com.github.mygreen.supercsv.builder.BeanMappingFactory;
3import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader;
4
5import java.nio.charset.Charset;
6import java.nio.file.Files;
7import java.io.File;
8
9import org.supercsv.prefs.CsvPreference;
10
11@Service
12public class CsvService {
13
14 @Autowired
15 private SpringBeanFactory beanFactory;
16
17 public void sampleSpring() {
18
19 // BeanMappingの作成 - SpringBeanFactoryを設定する
20 BeanMappingFactory beanMappingFactory = new BeanMappingFactory();
21 beanMappingFactory.getConfiguration().setBeanFactory(beanFactory);
22
23 // BeanMappingの作成
24 BeanMapping<UserCsv> beanMapping = mappingFactory.create(UserCsv.class);
25
26 CsvAnnotationBeanReader<UserCsv> csvReader = new CsvAnnotationBeanReader<>(
27 beanMapping,
28 Files.newBufferedReader(new File("user.csv").toPath(), Charset.forName("Windows-31j")),
29 CsvPreference.STANDARD_PREFERENCE);
30
31 //... 以下省略
32 }
33
34}
12.3. エラーメッセージの設定方法
SpringFrameworkの MessageSource
を利用する方法を説明します。
12.3.1. XMLによるコンテナの設定
XMLによる設定方法を説明します。
コンテナの定義の基本は次のようになります。
MessageSource
として、本ライブラリのエラーメッセージcom.github.mygreen.supercsv.localization.SuperCsvMessages
を読み込んでおきます。独自のエラーメッセージがあれば、追加で定義します。
com.github.mygreen.supercsv.localization.SpringMessageResolver
に、MessageSource
を渡します。
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- XMLによるコンテナの定義 -->
3<beans xmlns="http://www.springframework.org/schema/beans"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xmlns:context="http://www.springframework.org/schema/context"
6 xsi:schemaLocation="http://www.springframework.org/schema/beans
7 http://www.springframework.org/schema/beans/spring-beans.xsd
8 http://www.springframework.org/schema/context
9 http://www.springframework.org/schema/context/spring-context.xsd
10 ">
11
12 <!-- Spring標準のメッセージソースの定義 -->
13 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
14 <property name="basenames">
15 <list>
16 <value>com.github.mygreen.supercsv.localization.SuperCsvMessages</value>
17 <value>MyMessages</value>
18 </list>
19 </property>
20 </bean>
21
22 <!-- 本ライブラリのSpring用のMessgeResolverの定義 -->
23 <bean id="springMessageResolver" class="com.github.mygreen.supercsv.localization.SpringMessageResolver">
24 <property name="messageSource" ref="messageSource" />
25 </bean>
26
27</beans>
12.3.2. JavaConfigによるコンテナの設定
Spring Framework3.0から追加された、JavaソースによるSpringBean定義の方法を説明します。
JavaConfigによる設定を使用する場合は、Spring Frameworkのバージョンをできるだけ最新のものを使用してください。 特に、機能が豊富なバージョン4.0以上の使用を推奨します。
1import org.springframework.context.MessageSource;
2import org.springframework.context.annotation.Bean;
3import org.springframework.context.annotation.ComponentScan;
4import org.springframework.context.annotation.Configuration;
5import org.springframework.context.annotation.Description;
6import org.springframework.context.support.ResourceBundleMessageSource;
7
8import com.github.mygreen.supercsv.localization.SpringMessageResolver;
9
10
11// Javaによるコンテナの定義
12@Configuration
13@ComponentScan(basePackages="sample.spring")
14public class SuperCsvConfig {
15
16 @Bean
17 @Description("Spring標準のメッセージソースの定義")
18 public MessageSource messageSource() {
19 ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
20 messageSource.addBasenames(
21 "com.github.mygreen.supercsv.localization.SuperCsvMessages",
22 "MyMessages");
23 return messageSource;
24 }
25
26 @Bean
27 @Description("本ライブラリのSpring用のMessgeResolverの定義")
28 public SpringMessageResolver springMessageResolver() {
29 return new SpringMessageResolver(messageSource());
30 }
31
32}
12.3.3. SpringMessageResolverの使用方法
CsvExceptionConverter#setMessageResolver(...)
に、SpringBeanとして定義した SpringMessageResolver
を設定します。
さらに、 CsvAnnotationBeanReader#setExceptionConverter(...)
に、作成した CsvExceptionConverter を渡します。
1import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader;
2import com.github.mygreen.supercsv.localization.SpringMessageResolver;
3import com.github.mygreen.supercsv.validation.CsvExceptionConverter;
4
5import java.nio.charset.Charset;
6import java.nio.file.Files;
7import java.io.File;
8
9import org.supercsv.prefs.CsvPreference;
10
11@Service
12public class CsvService {
13
14 @Autowired
15 private SpringMessageResolver messageResolver;
16
17 public void sampleSpring() {
18
19 CsvAnnotationBeanReader<UserCsv> csvReader = new CsvAnnotationBeanReader<>(
20 UserCsv.class,
21 Files.newBufferedReader(new File("user.csv").toPath(), Charset.forName("Windows-31j")),
22 CsvPreference.STANDARD_PREFERENCE);
23
24 // CsvExceptionConverterの作成 - SpringMessageResolverを設定する
25 CsvExceptionConverter exceptionConverter = new CsvExceptionConverter();
26 exceptionConverter.setMessageResolver(messageResolver);
27
28 // CsvExceptionConverterを設定する
29 svReader.setExceptionConverter(exceptionConverter);
30
31 //... 以下省略
32 }
33
34}