From ee23fc462446b340ea0455f6b0c95425b86c86ee Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Wed, 9 Sep 2026 00:53:13 +0800 Subject: [PATCH 1/6] feat: add Character and Year converters (#1017) Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../converters/DefaultConverterLoader.java | 9 +++ .../CharacterStringConverter.java | 62 ++++++++++++++++ .../converters/year/YearStringConverter.java | 68 ++++++++++++++++++ .../CharacterStringConverterTest.java | 72 +++++++++++++++++++ .../year/YearStringConverterTest.java | 68 ++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java create mode 100644 fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java create mode 100644 fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java create mode 100644 fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java index f17d9b62c..353459755 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java @@ -44,6 +44,7 @@ import org.apache.fesod.sheet.converters.byteconverter.ByteBooleanConverter; import org.apache.fesod.sheet.converters.byteconverter.ByteNumberConverter; import org.apache.fesod.sheet.converters.byteconverter.ByteStringConverter; +import org.apache.fesod.sheet.converters.charconverter.CharacterStringConverter; import org.apache.fesod.sheet.converters.date.DateDateConverter; import org.apache.fesod.sheet.converters.date.DateNumberConverter; import org.apache.fesod.sheet.converters.date.DateStringConverter; @@ -78,6 +79,7 @@ import org.apache.fesod.sheet.converters.string.StringNumberConverter; import org.apache.fesod.sheet.converters.string.StringStringConverter; import org.apache.fesod.sheet.converters.url.UrlImageConverter; +import org.apache.fesod.sheet.converters.year.YearStringConverter; /** * Load default handler @@ -111,6 +113,8 @@ private static void initAllConverter() { putAllConverter(new ByteNumberConverter()); putAllConverter(new ByteStringConverter()); + putAllConverter(new CharacterStringConverter()); + putAllConverter(new DateNumberConverter()); putAllConverter(new DateStringConverter()); @@ -147,6 +151,8 @@ private static void initAllConverter() { putAllConverter(new StringNumberConverter()); putAllConverter(new StringStringConverter()); putAllConverter(new StringErrorConverter()); + + putAllConverter(new YearStringConverter()); allConverter = Collections.unmodifiableMap(allConverter); } @@ -156,6 +162,7 @@ private static void initDefaultWriteConverter() { putWriteConverter(new BigIntegerNumberConverter()); putWriteConverter(new BooleanBooleanConverter()); putWriteConverter(new ByteNumberConverter()); + putWriteConverter(new CharacterStringConverter()); putWriteConverter(new DateDateConverter()); putWriteConverter(new LocalDateTimeDateConverter()); putWriteConverter(new LocalDateDateConverter()); @@ -177,6 +184,7 @@ private static void initDefaultWriteConverter() { putWriteStringConverter(new BigIntegerStringConverter()); putWriteStringConverter(new BooleanStringConverter()); putWriteStringConverter(new ByteStringConverter()); + putWriteStringConverter(new CharacterStringConverter()); putWriteStringConverter(new DateStringConverter()); putWriteStringConverter(new LocalDateStringConverter()); putWriteStringConverter(new LocalDateTimeStringConverter()); @@ -187,6 +195,7 @@ private static void initDefaultWriteConverter() { putWriteStringConverter(new LongStringConverter()); putWriteStringConverter(new ShortStringConverter()); putWriteStringConverter(new StringStringConverter()); + putWriteStringConverter(new YearStringConverter()); defaultWriteConverter = Collections.unmodifiableMap(defaultWriteConverter); } diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java new file mode 100644 index 000000000..547340ac9 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.charconverter; + +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; + +/** + * Character and string converter + */ +public class CharacterStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Character.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Character convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String stringValue = cellData.getStringValue(); + if (stringValue == null || stringValue.isEmpty()) { + return null; + } + if (stringValue.length() > 1) { + throw new IllegalArgumentException( + "Can not convert '" + stringValue + "' to a character, the length must be 1"); + } + return stringValue.charAt(0); + } + + @Override + public WriteCellData convertToExcelData( + Character value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return new WriteCellData<>(String.valueOf(value)); + } +} diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java new file mode 100644 index 000000000..96205e610 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.year; + +import java.time.Year; +import java.time.format.DateTimeFormatter; +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; + +/** + * Year and string converter + */ +public class YearStringConverter implements Converter { + + private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("uuuu"); + + @Override + public Class supportJavaTypeKey() { + return Year.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Year convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Year.parse(cellData.getStringValue(), getFormatter(contentProperty, globalConfiguration)); + } + + @Override + public WriteCellData convertToExcelData( + Year value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return new WriteCellData<>(value.format(getFormatter(contentProperty, globalConfiguration))); + } + + private static DateTimeFormatter getFormatter( + ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return DEFAULT_FORMATTER; + } + return DateTimeFormatter.ofPattern( + contentProperty.getDateTimeFormatProperty().getFormat(), globalConfiguration.getLocale()); + } +} diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java new file mode 100644 index 000000000..a5d406a1a --- /dev/null +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.charconverter; + +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.testkit.Tags; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag(Tags.UNIT) +class CharacterStringConverterTest { + + private static final GlobalConfiguration GLOBAL_CONFIGURATION = new GlobalConfiguration(); + private final CharacterStringConverter converter = new CharacterStringConverter(); + + @Test + void supportJavaTypeKey() { + Assertions.assertEquals(Character.class, converter.supportJavaTypeKey()); + } + + @Test + void supportExcelTypeKey() { + Assertions.assertEquals(CellDataTypeEnum.STRING, converter.supportExcelTypeKey()); + } + + @Test + void convertToJavaDataReturnsSingleCharacter() { + Assertions.assertEquals( + Character.valueOf('A'), + converter.convertToJavaData(new ReadCellData<>("A"), null, GLOBAL_CONFIGURATION)); + } + + @Test + void convertToJavaDataReturnsNullForEmptyString() { + Assertions.assertNull(converter.convertToJavaData(new ReadCellData<>(""), null, GLOBAL_CONFIGURATION)); + } + + @Test + void convertToJavaDataThrowsOnLongerStrings() { + Assertions.assertThrows( + IllegalArgumentException.class, + () -> converter.convertToJavaData(new ReadCellData<>("AB"), null, GLOBAL_CONFIGURATION)); + } + + @Test + void convertToExcelDataWritesStringCell() { + WriteCellData cellData = converter.convertToExcelData('A', null, GLOBAL_CONFIGURATION); + Assertions.assertEquals(CellDataTypeEnum.STRING, cellData.getType()); + Assertions.assertEquals("A", cellData.getStringValue()); + } +} diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java new file mode 100644 index 000000000..fde611940 --- /dev/null +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.year; + +import java.time.DateTimeException; +import java.time.Year; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.testkit.Tags; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag(Tags.UNIT) +class YearStringConverterTest { + + private static final GlobalConfiguration GLOBAL_CONFIGURATION = new GlobalConfiguration(); + private final YearStringConverter converter = new YearStringConverter(); + + @Test + void supportJavaTypeKey() { + Assertions.assertEquals(Year.class, converter.supportJavaTypeKey()); + } + + @Test + void supportExcelTypeKey() { + Assertions.assertEquals(CellDataTypeEnum.STRING, converter.supportExcelTypeKey()); + } + + @Test + void convertToJavaDataUsesDefaultFormat() { + Assertions.assertEquals( + Year.of(2026), converter.convertToJavaData(new ReadCellData<>("2026"), null, GLOBAL_CONFIGURATION)); + } + + @Test + void convertToJavaDataThrowsOnInvalidValue() { + Assertions.assertThrows( + DateTimeException.class, + () -> converter.convertToJavaData(new ReadCellData<>("not-a-year"), null, GLOBAL_CONFIGURATION)); + } + + @Test + void convertToExcelDataUsesDefaultFormat() { + WriteCellData cellData = converter.convertToExcelData(Year.of(2026), null, GLOBAL_CONFIGURATION); + Assertions.assertEquals(CellDataTypeEnum.STRING, cellData.getType()); + Assertions.assertEquals("2026", cellData.getStringValue()); + } +} From 17412c880db28da07714e3ac0fa3326c3c231477 Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Wed, 9 Sep 2026 21:23:55 +0800 Subject: [PATCH 2/6] refactor: address review comments on Character and Year converters Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../CharacterStringConverter.java | 2 +- .../converters/year/YearStringConverter.java | 19 +++++----- .../apache/fesod/sheet/util/DateUtils.java | 35 +++++++++++++++++++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java index 547340ac9..d25ac1e34 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverter.java @@ -57,6 +57,6 @@ public Character convertToJavaData( @Override public WriteCellData convertToExcelData( Character value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new WriteCellData<>(String.valueOf(value)); + return new WriteCellData<>(value.toString()); } } diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java index 96205e610..4dd2f07e7 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/year/YearStringConverter.java @@ -20,21 +20,18 @@ package org.apache.fesod.sheet.converters.year; import java.time.Year; -import java.time.format.DateTimeFormatter; import org.apache.fesod.sheet.converters.Converter; import org.apache.fesod.sheet.enums.CellDataTypeEnum; import org.apache.fesod.sheet.metadata.GlobalConfiguration; import org.apache.fesod.sheet.metadata.data.ReadCellData; import org.apache.fesod.sheet.metadata.data.WriteCellData; import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.apache.fesod.sheet.util.DateUtils; /** * Year and string converter */ public class YearStringConverter implements Converter { - - private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("uuuu"); - @Override public Class supportJavaTypeKey() { return Year.class; @@ -48,21 +45,21 @@ public CellDataTypeEnum supportExcelTypeKey() { @Override public Year convertToJavaData( ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return Year.parse(cellData.getStringValue(), getFormatter(contentProperty, globalConfiguration)); + return DateUtils.parseYear( + cellData.getStringValue(), getYearFormat(contentProperty), globalConfiguration.getLocale()); } @Override public WriteCellData convertToExcelData( Year value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new WriteCellData<>(value.format(getFormatter(contentProperty, globalConfiguration))); + return new WriteCellData<>( + DateUtils.format(value, getYearFormat(contentProperty), globalConfiguration.getLocale())); } - private static DateTimeFormatter getFormatter( - ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + private static String getYearFormat(ExcelContentProperty contentProperty) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { - return DEFAULT_FORMATTER; + return null; } - return DateTimeFormatter.ofPattern( - contentProperty.getDateTimeFormatProperty().getFormat(), globalConfiguration.getLocale()); + return contentProperty.getDateTimeFormatProperty().getFormat(); } } diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java index d7927cc8d..a8d6c01db 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java @@ -32,6 +32,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.Year; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; @@ -105,6 +106,7 @@ public class DateUtils { public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss"; public static final String TIME_FORMAT_5 = "HH:mm"; public static final String TIME_FORMAT_8 = "HH:mm:ss"; + public static final String DEFAULT_YEAR_FORMAT = "yyyy"; private static final String MINUS = "-"; public static String defaultDateFormat = DATE_FORMAT_19; @@ -348,6 +350,39 @@ public static String format(LocalTime time, String timeFormat, Locale local) { return time.format(getCacheDateTimeFormat(timeFormat, local)); } + /** + * convert string to year + * + * @param yearString + * @param yearFormat + * @param local + * @return + */ + public static Year parseYear(String yearString, String yearFormat, Locale local) { + if (StringUtils.isEmpty(yearFormat)) { + yearFormat = DEFAULT_YEAR_FORMAT; + } + return Year.parse(yearString, getCacheDateTimeFormat(yearFormat, local)); + } + + /** + * Format year + * + * @param year Year + * @param yearFormat year format + * @param local local + * @return format string + */ + public static String format(Year year, String yearFormat, Locale local) { + if (year == null) { + return null; + } + if (StringUtils.isEmpty(yearFormat)) { + yearFormat = DEFAULT_YEAR_FORMAT; + } + return year.format(getCacheDateTimeFormat(yearFormat, local)); + } + /** * Format date * From 254a11e305316c9a7c4aa4490ebb5a0eaa7a20cf Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:48:19 +0800 Subject: [PATCH 3/6] refactor: align default year format field naming Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../main/java/org/apache/fesod/sheet/util/DateUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java index a8d6c01db..cb158c540 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java @@ -106,13 +106,14 @@ public class DateUtils { public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss"; public static final String TIME_FORMAT_5 = "HH:mm"; public static final String TIME_FORMAT_8 = "HH:mm:ss"; - public static final String DEFAULT_YEAR_FORMAT = "yyyy"; private static final String MINUS = "-"; public static String defaultDateFormat = DATE_FORMAT_19; public static String defaultLocalDateFormat = DATE_FORMAT_10; + public static String defaultYearFormat = "yyyy"; + public static final String DEFAULT_LOCAL_TIME_FORMAT = TIME_FORMAT_8; public static final int SECONDS_PER_MINUTE = 60; @@ -360,7 +361,7 @@ public static String format(LocalTime time, String timeFormat, Locale local) { */ public static Year parseYear(String yearString, String yearFormat, Locale local) { if (StringUtils.isEmpty(yearFormat)) { - yearFormat = DEFAULT_YEAR_FORMAT; + yearFormat = defaultYearFormat; } return Year.parse(yearString, getCacheDateTimeFormat(yearFormat, local)); } @@ -378,7 +379,7 @@ public static String format(Year year, String yearFormat, Locale local) { return null; } if (StringUtils.isEmpty(yearFormat)) { - yearFormat = DEFAULT_YEAR_FORMAT; + yearFormat = defaultYearFormat; } return year.format(getCacheDateTimeFormat(yearFormat, local)); } From faf220704663986d570ae5c5e344a8952ec38da2 Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:00:10 +0800 Subject: [PATCH 4/6] test: cover YearStringConverter and DateUtils year scenarios Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../year/YearStringConverterTest.java | 28 +++++++++++++++++++ .../fesod/sheet/util/DateUtilsTest.java | 24 ++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java index fde611940..64959c3db 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java @@ -21,10 +21,13 @@ import java.time.DateTimeException; import java.time.Year; +import java.util.Locale; import org.apache.fesod.sheet.enums.CellDataTypeEnum; import org.apache.fesod.sheet.metadata.GlobalConfiguration; import org.apache.fesod.sheet.metadata.data.ReadCellData; import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.DateTimeFormatProperty; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; import org.apache.fesod.sheet.testkit.Tags; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Tag; @@ -65,4 +68,29 @@ void convertToExcelDataUsesDefaultFormat() { Assertions.assertEquals(CellDataTypeEnum.STRING, cellData.getType()); Assertions.assertEquals("2026", cellData.getStringValue()); } + + @Test + void convertToExcelDataUsesCustomFormat() { + ExcelContentProperty contentProperty = new ExcelContentProperty(); + contentProperty.setDateTimeFormatProperty(new DateTimeFormatProperty("'Y'yyyy", null)); + WriteCellData cellData = converter.convertToExcelData(Year.of(2026), contentProperty, GLOBAL_CONFIGURATION); + Assertions.assertEquals("Y2026", cellData.getStringValue()); + } + + @Test + void convertToExcelDataRespectsLocaleForEraPatterns() { + GlobalConfiguration chinaConfiguration = new GlobalConfiguration(); + chinaConfiguration.setLocale(Locale.CHINA); + GlobalConfiguration usConfiguration = new GlobalConfiguration(); + usConfiguration.setLocale(Locale.US); + ExcelContentProperty contentProperty = new ExcelContentProperty(); + contentProperty.setDateTimeFormatProperty(new DateTimeFormatProperty("G y", null)); + + WriteCellData chinaCellData = + converter.convertToExcelData(Year.of(2026), contentProperty, chinaConfiguration); + Assertions.assertEquals("公元 2026", chinaCellData.getStringValue()); + + WriteCellData usCellData = converter.convertToExcelData(Year.of(2026), contentProperty, usConfiguration); + Assertions.assertEquals("AD 2026", usCellData.getStringValue()); + } } diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java index dc845345b..2238a5091 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java @@ -26,6 +26,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.Year; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; @@ -499,4 +500,27 @@ void test_removeThreadLocalCache() throws NoSuchFieldException, IllegalAccessExc Assertions.assertNull(((ThreadLocal) f2.get(null)).get()); Assertions.assertNull(((ThreadLocal) f3.get(null)).get()); } + + @Test + void test_parseYearUsesDefaultFormat() { + Assertions.assertEquals(Year.of(2026), DateUtils.parseYear("2026", null, null)); + Assertions.assertEquals(Year.of(2026), DateUtils.parseYear("2026", null, Locale.US)); + } + + @Test + void test_parseYearUsesCustomFormat() { + Assertions.assertEquals(Year.of(2026), DateUtils.parseYear("26", "uu", null)); + } + + @Test + void test_formatYearUsesDefaultFormat() { + Assertions.assertEquals("2026", DateUtils.format(Year.of(2026), null, null)); + Assertions.assertEquals("2026", DateUtils.format(Year.of(2026), null, Locale.US)); + } + + @Test + void test_formatYearRespectsLocaleForEraPatterns() { + Assertions.assertEquals("公元 2026", DateUtils.format(Year.of(2026), "G y", Locale.CHINA)); + Assertions.assertEquals("AD 2026", DateUtils.format(Year.of(2026), "G y", Locale.US)); + } } From 7986ca11355a849d79a74d3d37e0cef8d33f6579 Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Wed, 16 Sep 2026 07:07:14 +0800 Subject: [PATCH 5/6] fix: register the Year converter under the wildcard write key Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../converters/DefaultConverterLoader.java | 1 + .../year/YearStringConverterTest.java | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java index 353459755..dbebb5d8d 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java @@ -173,6 +173,7 @@ private static void initDefaultWriteConverter() { putWriteConverter(new LongNumberConverter()); putWriteConverter(new ShortNumberConverter()); putWriteConverter(new StringStringConverter()); + putWriteConverter(new YearStringConverter()); putWriteConverter(new FileImageConverter()); putWriteConverter(new InputStreamImageConverter()); putWriteConverter(new ByteArrayImageConverter()); diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java index 64959c3db..44959862d 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/year/YearStringConverterTest.java @@ -19,10 +19,19 @@ package org.apache.fesod.sheet.converters.year; +import java.io.File; import java.time.DateTimeException; import java.time.Year; +import java.util.Collections; +import java.util.List; import java.util.Locale; +import lombok.Getter; +import lombok.Setter; +import org.apache.fesod.sheet.FesodSheet; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.apache.fesod.sheet.context.AnalysisContext; import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.event.AnalysisEventListener; import org.apache.fesod.sheet.metadata.GlobalConfiguration; import org.apache.fesod.sheet.metadata.data.ReadCellData; import org.apache.fesod.sheet.metadata.data.WriteCellData; @@ -93,4 +102,47 @@ void convertToExcelDataRespectsLocaleForEraPatterns() { WriteCellData usCellData = converter.convertToExcelData(Year.of(2026), contentProperty, usConfiguration); Assertions.assertEquals("AD 2026", usCellData.getStringValue()); } + + @Test + void yearFieldRoundTripsThroughFesodSheet() throws Exception { + File file = File.createTempFile("fesod-year", ".xlsx"); + file.deleteOnExit(); + YearWriteData row = new YearWriteData(); + row.setFlag(Year.of(2026)); + + // A Year field is written through the full write path: without a wildcard registration + // (putWriteConverter) the xlsx lookup key (Year, null) finds no converter and throws. + FesodSheet.write(file, YearWriteData.class).sheet().doWrite(Collections.singletonList(row)); + + List rows = FesodSheet.read(file, YearReadData.class, new YearReadListener()) + .sheet() + .doReadSync(); + Assertions.assertEquals(1, rows.size()); + Assertions.assertEquals(Year.of(2026), rows.get(0).getFlag()); + } + + @Getter + @Setter + public static class YearWriteData { + + @ExcelProperty("flag") + private Year flag; + } + + @Getter + @Setter + public static class YearReadData { + + @ExcelProperty("flag") + private Year flag; + } + + public static class YearReadListener extends AnalysisEventListener { + + @Override + public void invoke(YearReadData data, AnalysisContext context) {} + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} + } } From 6d65c0fce8bc19d39c17bafd9d584ef2a3956c0b Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Wed, 16 Sep 2026 10:39:35 +0800 Subject: [PATCH 6/6] test: cover Character field round trip through FesodSheet Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- .../CharacterStringConverterTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java index a5d406a1a..b8143722b 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/charconverter/CharacterStringConverterTest.java @@ -19,7 +19,16 @@ package org.apache.fesod.sheet.converters.charconverter; +import java.io.File; +import java.util.Collections; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.apache.fesod.sheet.FesodSheet; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.apache.fesod.sheet.context.AnalysisContext; import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.event.AnalysisEventListener; import org.apache.fesod.sheet.metadata.GlobalConfiguration; import org.apache.fesod.sheet.metadata.data.ReadCellData; import org.apache.fesod.sheet.metadata.data.WriteCellData; @@ -69,4 +78,45 @@ void convertToExcelDataWritesStringCell() { Assertions.assertEquals(CellDataTypeEnum.STRING, cellData.getType()); Assertions.assertEquals("A", cellData.getStringValue()); } + + @Test + void characterFieldRoundTripsThroughFesodSheet() throws Exception { + File file = File.createTempFile("fesod-character", ".xlsx"); + file.deleteOnExit(); + CharacterWriteData row = new CharacterWriteData(); + row.setFlag('A'); + + FesodSheet.write(file, CharacterWriteData.class).sheet().doWrite(Collections.singletonList(row)); + + List rows = FesodSheet.read(file, CharacterReadData.class, new CharacterReadListener()) + .sheet() + .doReadSync(); + Assertions.assertEquals(1, rows.size()); + Assertions.assertEquals(Character.valueOf('A'), rows.get(0).getFlag()); + } + + @Getter + @Setter + public static class CharacterWriteData { + + @ExcelProperty("flag") + private Character flag; + } + + @Getter + @Setter + public static class CharacterReadData { + + @ExcelProperty("flag") + private Character flag; + } + + public static class CharacterReadListener extends AnalysisEventListener { + + @Override + public void invoke(CharacterReadData data, AnalysisContext context) {} + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} + } }