-------------------------------------------------------- SpringBeanFactoryの設定方法 -------------------------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XMLによるコンテナの設定 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XMLによる設定方法を説明します。 コンテナの定義の基本は次のようになります。 * アノテーションによるDIの有効化を行います。 * コンポーネントスキャン対象のパッケージの指定を行います。 * ``com.github.mygreen.supercsv.builder.SpringBeanFactory`` をSpringBeanとして登録します。 .. sourcecode:: xml :linenos: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ JavaConfigによるコンテナの設定 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Spring Framework3.0から追加された、JavaソースによるSpringBean定義の方法を説明します。 JavaConfigによる設定を使用する場合は、Spring Frameworkのバージョンをできるだけ最新のものを使用してください。 特に、機能が豊富なバージョン4.0以上の使用を推奨します。 .. sourcecode:: java :linenos: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Description; import com.github.mygreen.supercsv.builder.SpringBeanFactory; // Javaによるコンテナの定義 @Configuration @ComponentScan(basePackages="sample.spring") public class SuperCsvConfig { @Bean @Description("Springのコンテナを経由するCSV用のBeanFactoryの定義") public SpringBeanFactory springBeanFactory() { return new SpringBeanFactory(); } } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SpringBeanとしての定義 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ステレオタイプのアノテーション ``@Component/@Service/@Reposition/@Controller`` をサポートしているため、 これらを使いSpringBeanを定義します。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 独自の書式の作成 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 独自の書式の ``TextFormatter`` を定義する際には、スコープを *proptotype* にします。 読み込み時のエラーメッセージが、カラムごとに異なる場合があるため、インスタンスを別にします。 .. sourcecode:: java :linenos: import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import com.github.mygreen.supercsv.cellprocessor.format.AbstractTextFormatter; import com.github.mygreen.supercsv.cellprocessor.format.TextParseException; /** * {@link SampleType}に対するTextFromatterの実装 */ @Scope("prototype") @Component public class SampleTypeFormatter extends AbstractTextFormatter { // SpringBeanのインジェクション @Autowired private SampleService sampleService; @Override public SampleType parse(final String text) { try { // 業務ロジックなので省略 } catch(Exception e) { throw new TextParseException(text, SampleType.class, e); } } @Override public String print(final SampleType object) { // 業務ロジックなので省略 } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 独自の変換/検証の作成 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 検証用の ``ConstraintProcessorFactory`` の例として、DBにユーザが存在するかチェックするCellProcessorで説明します。 変換用の ``ConversionProcessorFactory`` も同様の実装方法になります。 * ``ConstraintProcessorFactory`` はシングルトンで定義します。 * CellProcessorは、カラムごとに固有なインスタンスにするため、Springのコンテナ管理外とします。 * CellProcessor内で、SpringBeanを利用したい場合は、 *ConstraintProcessorFactory* クラスでインジェクションしておき、 それをコンストラクタやsetterメソッドで渡すようにします。 .. sourcecode:: java :linenos: import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.supercsv.cellprocessor.ift.CellProcessor; import com.github.mygreen.supercsv.builder.BuildType; import com.github.mygreen.supercsv.builder.Configuration; import com.github.mygreen.supercsv.builder.FieldAccessor; import com.github.mygreen.supercsv.cellprocessor.ConstraintProcessorFactory; import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter; /** * ユーザ名がDBに存在するか検証するCellProcessorを作成するクラス */ @Component public class UserNameExistFactory implements ConstraintProcessorFactory { // SpringBeanのインジェクション @Autowired private UserService userService; @Override public Optional create(final CsvUserNameExist anno, final Optional next, final FieldAccessor field, final TextFormatter formatter, final Configuration config) { // UserService はCellProcessorに渡す final UserNameExist processor = next.map(n -> new UserNameExist(userService, n)) .orElseGet(() -> new UserNameExist(userService)); processor.setValidationMessage(anno.message()); return Optional.of(processor); } } *CellProcessor* は、コンストラクタで渡されたSpringBean(UserService)のメソッドを呼び出します。 .. sourcecode:: java :linenos: import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.cellprocessor.ift.StringCellProcessor; import org.supercsv.util.CsvContext; import com.github.mygreen.supercsv.cellprocessor.ValidationCellProcessor; /** * ユーザ名の存在チェックを行う制約のCellProcessor */ public class UserNameExist extends ValidationCellProcessor implements StringCellProcessor { private final UserService userService; public UserNameExist(final UserService userService) { checkPreconditions(userService); this.userService = userService; } public UserNameExist(final UserService userService, final CellProcessor next) { super(next); checkPreconditions(userService); this.userService = userService; } private static void checkPreconditions(final UserService userService) { if(userService == null) { throw new NullPointerException("userService should not be null"); } } @Override public T execute(final Object value, final CsvContext context) { if(value == null) { return next.execute(value, context); } final String result = value.toString(); // サービスのメソッドの呼び出し if(!userService.existByUserName(result)) { throw createValidationException(context) .messageFormat("%s dose not found user name.", result) .rejectedValue(result) .build(); } return next.execute(value, context); } } アノテーションの作成法補は、通常と変わりません。 メタアノテーション *@CsvConstraint* で ConstraintProcessorFactoryを実装したクラスUserNameExistFactoryを指定します。 .. sourcecode:: java :linenos: import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * ユーザが存在するかチェックするためのアノテーション */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(CsvUserNameExist.List.class) @CsvConstraint(value=UserNameExistFactory.class) public @interface CsvUserNameExist { String message() default "{sample.CsvUserNameExist.message}"; Class[] groups() default {}; int order() default 0; @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { CsvUserNameExist[] value(); } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 独自のProcessorBuilderクラスの作成 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 独自のクラスタイプのProcessorBuilderは、自身をSpringBeanとして登録します。 通常は、シングルトンでかまいません。 .. sourcecode:: java :linenos: import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.github.mygreen.supercsv.builder.AbstractProcessorBuilder; import com.github.mygreen.supercsv.builder.Configuration; import com.github.mygreen.supercsv.builder.FieldAccessor; import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter; @Component public class SampleTypeProcessorBuilder extends AbstractProcessorBuilder { @Autowired private SampleTypeFormatter formatter; @Autowired private SampleConstraintFactory sampleConstaintFactory; @Override protected void init() { super.init(); // 制約や変換用のアノテーションの登録 // @CsvConstaint/@CsvCoversionの関連付けを省略し手いる場合に登録する registerForConstraint(CsvSampleConstraint.class, sampleConstaintFactory); } @Override protected TextFormatter getDefaultFormatter(final FieldAccessor field, final Configuration config) { return formatter; } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CsvValidator の作成 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *CsvValidator* クラスは、シングルトンで管理します。 SpringBeanをインジェクションしたいものがあれば行います。 .. sourcecode:: java :linenos: import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.github.mygreen.supercsv.validation.CsvBindingErrors; import com.github.mygreen.supercsv.validation.CsvValidator; import com.github.mygreen.supercsv.validation.ValidationContext; /** * {@link UserCsv}に対するValidator * */ @Component public class UserValidator implements CsvValidator { // SpringBeanのインジェクション @Autowired private UserService userService; @Override public void validate(final UserCsv record, final CsvBindingErrors bindingErrors, final ValidationContext validationContext) { // 業務ロジックなので省略 } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ リスナクラスの作成 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ リスナクラスは、POJOであるため、SpringBeanをインジェクションしたいものがあれば行います。 .. sourcecode:: java :linenos: import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.github.mygreen.supercsv.annotation.CsvPostRead; import com.github.mygreen.supercsv.annotation.CsvPreWrite; /** * {@link UserCsv}に対するリスナクラス * */ @Component public class UserListener { @Autowired private UserService userSerivce; @CsvPreWrite @CsvPostRead public void validate(final UserCsv record) { // 業務ロジックなので省略 } } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CsvBeanの定義 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CSVのBeanの定義では、SpringBeanとして定義したクラスを指定します。 .. sourcecode:: java :linenos: import com.github.mygreen.supercsv.annotation.CsvBean; import com.github.mygreen.supercsv.annotation.CsvColumn; import com.github.mygreen.supercsv.annotation.constraint.CsvRequire; import com.github.mygreen.supercsv.annotation.format.CsvFormat; import com.github.mygreen.supercsv.validation.beanvalidation.CsvBeanValidator; @CsvBean(header=true, validator=UserValidator.class, // Spring管理のValidatorの指定 listener=UserListener.class // Spring管理のリスナクラスの指定 ) public class UserCsv { // Srping管理のFormatterを指定する場合。 @CsvColumn(number=1, label="タイプ") @CsvFormat(formatter=SampleTypeFormatter.class) private SampleType sampleType1; // Spring管理のConstraintProcessorFactory を利用している検証用アノテーション @CsvColumn(number=2, label="名前") @CsvUserNameExist private String name; // Spring管理のProcessorBuilderを指定する場合 @CsvColumn(number=3, label="ホームページ", builder=SampleTypeProcessorBuilder.class) private SampleType sampleType2; // setter/getterは省略 } .. note:: SpringBeanの管理外のクラスを指定した場合は、通常の方法としてインスタンスが作成されます。 ただし、管理外のクラスでもインジェクション用のアノテーション(@Resource/@Autowired)があれば、 インジェクションされます。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SpringBeanFactoryの使用方法 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``BeanMappingFactory#getConfiguration()`` 取得できる、システム設定に、SpringBeanFactoryを設定します。 .. sourcecode:: java :linenos: import com.github.mygreen.supercsv.builder.BeanMapping; import com.github.mygreen.supercsv.builder.BeanMappingFactory; import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader; import java.nio.charset.Charset; import java.nio.file.Files; import java.io.File; import org.supercsv.prefs.CsvPreference; @Service public class CsvService { @Autowired private SpringBeanFactory beanFactory; public void sampleSpring() { // BeanMappingの作成 - SpringBeanFactoryを設定する BeanMappingFactory beanMappingFactory = new BeanMappingFactory(); beanMappingFactory.getConfiguration().setBeanFactory(beanFactory); // BeanMappingの作成 BeanMapping beanMapping = mappingFactory.create(UserCsv.class); CsvAnnotationBeanReader csvReader = new CsvAnnotationBeanReader<>( beanMapping, Files.newBufferedReader(new File("user.csv").toPath(), Charset.forName("Windows-31j")), CsvPreference.STANDARD_PREFERENCE); //... 以下省略 } }