diff --git a/src/test/data/external.xlsx b/src/test/data/external.xlsx new file mode 100644 index 00000000..bc3d6d9f Binary files /dev/null and b/src/test/data/external.xlsx differ diff --git a/src/test/java/test/external/ExternalSheet.java b/src/test/java/test/external/ExternalSheet.java new file mode 100644 index 00000000..5944e67d --- /dev/null +++ b/src/test/java/test/external/ExternalSheet.java @@ -0,0 +1,80 @@ +package test.external; + +import java.time.LocalDate; + +import javax.validation.constraints.NotEmpty; + +import org.hibernate.validator.constraints.Length; + +import com.gh.mygreen.xlsmapper.annotation.LabelledCellType; +import com.gh.mygreen.xlsmapper.annotation.XlsConverter; +import com.gh.mygreen.xlsmapper.annotation.XlsDateTimeConverter; +import com.gh.mygreen.xlsmapper.annotation.XlsEnumConverter; +import com.gh.mygreen.xlsmapper.annotation.XlsLabelledCell; +import com.gh.mygreen.xlsmapper.annotation.XlsSheet; + +import test.external.PostalCode.PostalCellConverterFactory; + +/** + * サンプルのシート。 + *

外部パッケージの核に尿 + * + * @author T.TSUCHIE + * + */ +@XlsSheet(name = "外部パッケージ") +public class ExternalSheet { + + public static enum Role { + Admin, Developer, Repoter + } + + @NotEmpty + @Length(max = 20) + @XlsLabelledCell(label = "名前", type = LabelledCellType.Right) + private String name; + + @XlsLabelledCell(label = "入社日付", type = LabelledCellType.Right) + @XlsDateTimeConverter(excelPattern = "YYYY/MM/DD") + private LocalDate joinedDate; + + @XlsLabelledCell(label = "ロール", type = LabelledCellType.Right) + @XlsEnumConverter(ignoreCase = true) + private Role role; + + @XlsLabelledCell(label = "郵便番号", type = LabelledCellType.Right) + @XlsConverter(PostalCellConverterFactory.class) + private PostalCode postalCode; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDate getJoinedDate() { + return joinedDate; + } + + public void setJoinedDate(LocalDate joinedDate) { + this.joinedDate = joinedDate; + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } + + public PostalCode getPostalCode() { + return postalCode; + } + + public void setPostalCode(PostalCode postalCode) { + this.postalCode = postalCode; + } +} diff --git a/src/test/java/test/external/ExternalTest.java b/src/test/java/test/external/ExternalTest.java new file mode 100644 index 00000000..73825b28 --- /dev/null +++ b/src/test/java/test/external/ExternalTest.java @@ -0,0 +1,184 @@ +package test.external; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +import javax.validation.constraints.NotEmpty; + +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.gh.mygreen.xlsmapper.AnnotationInvalidException; +import com.gh.mygreen.xlsmapper.SheetFinder; +import com.gh.mygreen.xlsmapper.SheetNotFoundException; +import com.gh.mygreen.xlsmapper.XlsMapper; +import com.gh.mygreen.xlsmapper.annotation.LabelledCellType; +import com.gh.mygreen.xlsmapper.annotation.XlsLabelledCell; +import com.gh.mygreen.xlsmapper.annotation.XlsSheet; +import com.gh.mygreen.xlsmapper.util.Utils; +import com.gh.mygreen.xlsmapper.validation.ObjectError; +import com.gh.mygreen.xlsmapper.validation.SheetBindingErrors; +import com.gh.mygreen.xlsmapper.validation.SheetErrorFormatter; +import com.gh.mygreen.xlsmapper.validation.beanvalidation.SheetBeanValidator; +import com.gh.mygreen.xlsmapper.xml.AnnotationReadException; +import com.gh.mygreen.xlsmapper.xml.AnnotationReader; + +/** + * 外部パッケージのテスト。 + * + * @author T.TSUCHIE + * + */ +public class ExternalTest { + + /** + * テスト用に動的にシート名を切り替えるSheetFinder + * + */ + private static class CustomSheetFinder extends SheetFinder { + + private String mySheetName; + + CustomSheetFinder(String mySheetName) { + this.mySheetName = mySheetName; + } + + @Override + public Sheet[] findForLoading(final Workbook workbook, final XlsSheet sheetAnno, + final AnnotationReader annoReader, final Class beanClass) + throws SheetNotFoundException, AnnotationInvalidException, AnnotationReadException { + + if(Utils.isNotEmpty(mySheetName)) { + // シート名から取得する。 + final Sheet xlsSheet = workbook.getSheet(mySheetName); + if(xlsSheet == null) { + throw new SheetNotFoundException(mySheetName); + } + return new Sheet[]{ xlsSheet }; + } + return super.findForLoading(workbook, sheetAnno, annoReader, beanClass); + } + } + + @BeforeClass + public static void setup() { + System.setProperty("xlsmapper.jexlRestricted", "true"); +// System.setProperty("xlsmapper.jexlPermissions", "test.external.*"); + } + + @Test + public void testRead_normal() throws Exception { + + XlsMapper mapper = new XlsMapper(); + mapper.getConfiguration().setContinueTypeBindFailure(true); + + // シートの読み込み + try(InputStream in = new FileInputStream("src/test/data/external.xlsx")) { + + SheetBindingErrors bindingErrors = mapper.loadDetail(in, ExternalSheet.class); + + ExternalSheet sheet = bindingErrors.getTarget(); + + // 入力値検証 + SheetBeanValidator validatorAdaptor = new SheetBeanValidator(); + validatorAdaptor.validate(sheet, bindingErrors); + + List errors = bindingErrors.getAllErrors(); + assertThat(errors, hasSize(0)); + + } + } + + @Test + public void testRead_validationError_Enum() throws Exception { + XlsMapper mapper = new XlsMapper(); + mapper.getConfiguration() + .setContinueTypeBindFailure(true) + .setSheetFinder(new CustomSheetFinder("エラー_Enum")); + + + // シートの読み込み + try(InputStream in = new FileInputStream("src/test/data/external.xlsx")) { + + SheetBindingErrors bindingErrors = mapper.loadDetail(in, ExternalSheet.class); + + ExternalSheet sheet = bindingErrors.getTarget(); + + // 入力値検証 + SheetBeanValidator validatorAdaptor = new SheetBeanValidator(); + validatorAdaptor.validate(sheet, bindingErrors); + + SheetErrorFormatter errorFormatter = new SheetErrorFormatter(); + + List errors = bindingErrors.getAllErrors(); + assertThat(errors, hasSize(1)); + assertThat(errorFormatter.format(errors.get(0)), is("[エラー_Enum]:ロール - セル(C5)の値'aaa'は、何れかの値[Admin, Developer, Repoter]で設定してください。")); + + } + } + + @Test + public void testRead_validationError_CutomType() throws Exception { + XlsMapper mapper = new XlsMapper(); + mapper.getConfiguration() + .setContinueTypeBindFailure(true) + .setSheetFinder(new CustomSheetFinder("エラー_カスタムタイプ")); + + + // シートの読み込み + try(InputStream in = new FileInputStream("src/test/data/external.xlsx")) { + + SheetBindingErrors bindingErrors = mapper.loadDetail(in, ExternalSheet.class); + + ExternalSheet sheet = bindingErrors.getTarget(); + + // 入力値検証 + SheetBeanValidator validatorAdaptor = new SheetBeanValidator(); + validatorAdaptor.validate(sheet, bindingErrors); + + SheetErrorFormatter errorFormatter = new SheetErrorFormatter(); + + List errors = bindingErrors.getAllErrors(); + assertThat(errors, hasSize(1)); + assertThat(errorFormatter.format(errors.get(0)), is("[エラー_カスタムタイプ]:郵便番号 - セル(C6)の値'0001111'の型変換に失敗しました。")); + + } + } + + @Test + public void testRead_AnnoError() throws Exception { + + XlsMapper mapper = new XlsMapper(); + mapper.getConfiguration().setContinueTypeBindFailure(true); + + // シートの読み込み + try(InputStream in = new FileInputStream("src/test/data/external.xlsx")) { + + AnnotationInvalidException exception = assertThrows(AnnotationInvalidException.class, () -> + mapper.loadDetail(in, ExeranalWronngAnnoSheet.class)); + + assertThat(exception.getMessage(), is("'test.external.ExternalTest$ExeranalWronngAnnoSheet'において、アノテーション'@XlsSheet'の何れか属性[name or number or regex]の設定は必須です。")); + + } + } + + /** + * アノテーションの定義間違い。 + *

シートの指定がない。 + * + */ + @XlsSheet + public static class ExeranalWronngAnnoSheet { + + @NotEmpty + @XlsLabelledCell(label = "名前", type = LabelledCellType.Right) + private String name; + + } +} diff --git a/src/test/java/test/external/PostalCode.java b/src/test/java/test/external/PostalCode.java new file mode 100644 index 00000000..fd97acb6 --- /dev/null +++ b/src/test/java/test/external/PostalCode.java @@ -0,0 +1,167 @@ +package test.external; + +import java.io.Serializable; +import java.util.Optional; + +import org.apache.poi.ss.usermodel.Cell; + +import com.gh.mygreen.xlsmapper.Configuration; +import com.gh.mygreen.xlsmapper.cellconverter.BaseCellConverter; +import com.gh.mygreen.xlsmapper.cellconverter.CellConverter; +import com.gh.mygreen.xlsmapper.cellconverter.CellConverterFactory; +import com.gh.mygreen.xlsmapper.cellconverter.CellConverterFactorySupport; +import com.gh.mygreen.xlsmapper.cellconverter.TypeBindException; +import com.gh.mygreen.xlsmapper.fieldaccessor.FieldAccessor; +import com.gh.mygreen.xlsmapper.textformatter.TextFormatter; +import com.gh.mygreen.xlsmapper.textformatter.TextParseException; +import com.gh.mygreen.xlsmapper.util.Utils; + +/** + * 外部パッケージの独自の型。 + *

郵便番号を表現する。 + * + * @author T.TSUCHIE + * + */ +public class PostalCode implements Serializable { + + private static final String SEPARATOR = "-"; + + /** 上3桁 */ + private String code1; + + /** 下4桁 */ + private String code2; + + public PostalCode(final String value) { + if(!parse(value)) { + throw new IllegalArgumentException("not support format : " + value); + } + } + + public boolean parse(final String value) { + + if(Utils.isEmpty(value)) { + return false; + } + + String[] splits = value.split(SEPARATOR); + if(splits.length != 2) { + return false; + } + + if(splits[0].length() != 3) { + return false; + } + + this.code1 = splits[0]; + + if(splits[1].length() != 4) { + return false; + } + + this.code2 = splits[1]; + + return true; + } + + @Override + public String toString() { + return code1 + SEPARATOR + code2; + } + + public String getCode1() { + return code1; + } + + public String getCode2() { + return code2; + } + + /** + * 変換用のCellConverter + * + */ + public static class PostalCellConverter extends BaseCellConverter { + + public PostalCellConverter(FieldAccessor field, Configuration config) { + super(field, config); + } + + @Override + protected PostalCode parseCell(Cell evaluatedCell, String formattedValue) throws TypeBindException { + + try { + return getTextFormatter().parse(formattedValue); + } catch(TextParseException e) { + throw newTypeBindExceptionOnParse(e, evaluatedCell, formattedValue); + } + } + + @Override + protected void setupCell(Cell cell, Optional cellValue) throws TypeBindException { + + if (cellValue.isPresent()) { + String text = getTextFormatter().format(cellValue.get()); + cell.setCellValue(text); + } else { + cell.setBlank(); + } + + } + + } + + /** + * 変換処理用のCellConverterFactory + * + * + * @author T.TSUCHIE + * + */ + public static class PostalCellConverterFactory extends CellConverterFactorySupport implements CellConverterFactory { + + @Override + public CellConverter create(FieldAccessor accessor, Configuration config) { + + final PostalCellConverter cellConverter = new PostalCellConverter(accessor, config); + setupCellConverter(cellConverter, accessor, config); + return cellConverter; + } + + @Override + protected void setupCustom(BaseCellConverter cellConverter, FieldAccessor field, Configuration config) { + // no implements + } + + @Override + protected TextFormatter createTextFormatter(FieldAccessor field, Configuration config) { + + return new TextFormatter() { + + @Override + public PostalCode parse(String text) throws TextParseException { + + try { + return new PostalCode(text); + } catch(IllegalArgumentException e) { + throw new TextParseException(text, PostalCode.class); + } + + } + + @Override + public String format(PostalCode value) { + if (value == null) { + return ""; + } + + return value.toString(); + } + + }; + } + + } + +} diff --git a/src/test/java/test/external/package-info.java b/src/test/java/test/external/package-info.java new file mode 100644 index 00000000..a0323d28 --- /dev/null +++ b/src/test/java/test/external/package-info.java @@ -0,0 +1,6 @@ +/** + * xlmapperとは異なるテスト用の外部パッケージ。 + * JEXL3.4のパーミッション外部パッケージでのテストのために使用する。 + * + */ +package test.external;