From cc279260fdca8d6873b84fe2562f440e5329912e Mon Sep 17 00:00:00 2001 From: AhmedYoussef98 Date: Wed, 23 Sep 2026 14:48:08 +0300 Subject: [PATCH] feat: add java.sql.Clob converter --- .../converters/DefaultConverterLoader.java | 5 ++ .../converters/clob/ClobStringConverter.java | 69 +++++++++++++++++++ .../DefaultConverterLoaderTest.java | 17 +++++ .../clob/ClobStringConverterTest.java | 60 ++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/clob/ClobStringConverter.java create mode 100644 fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/clob/ClobStringConverterTest.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..4f5e6cb7a 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.clob.ClobStringConverter; import org.apache.fesod.sheet.converters.date.DateDateConverter; import org.apache.fesod.sheet.converters.date.DateNumberConverter; import org.apache.fesod.sheet.converters.date.DateStringConverter; @@ -111,6 +112,8 @@ private static void initAllConverter() { putAllConverter(new ByteNumberConverter()); putAllConverter(new ByteStringConverter()); + putAllConverter(new ClobStringConverter()); + putAllConverter(new DateNumberConverter()); putAllConverter(new DateStringConverter()); @@ -166,6 +169,7 @@ private static void initDefaultWriteConverter() { putWriteConverter(new LongNumberConverter()); putWriteConverter(new ShortNumberConverter()); putWriteConverter(new StringStringConverter()); + putWriteConverter(new ClobStringConverter()); putWriteConverter(new FileImageConverter()); putWriteConverter(new InputStreamImageConverter()); putWriteConverter(new ByteArrayImageConverter()); @@ -187,6 +191,7 @@ private static void initDefaultWriteConverter() { putWriteStringConverter(new LongStringConverter()); putWriteStringConverter(new ShortStringConverter()); putWriteStringConverter(new StringStringConverter()); + putWriteStringConverter(new ClobStringConverter()); defaultWriteConverter = Collections.unmodifiableMap(defaultWriteConverter); } diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/clob/ClobStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/clob/ClobStringConverter.java new file mode 100644 index 000000000..5e2342a35 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/clob/ClobStringConverter.java @@ -0,0 +1,69 @@ +/* + * 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.clob; + +import java.io.Reader; +import java.sql.Clob; +import javax.sql.rowset.serial.SerialClob; +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; + +/** + * Clob and string converter. Clob data is represented as a string cell; reads return a + * {@link SerialClob} so callers receive a usable, detached JDBC Clob value. + */ +public class ClobStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Clob.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Clob convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws Exception { + // Materialize cell text into a detached JDBC Clob, avoiding a database-specific Clob implementation. + return new SerialClob(cellData.getStringValue().toCharArray()); + } + + @Override + public WriteCellData convertToExcelData( + Clob value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws Exception { + StringBuilder text = new StringBuilder(); + char[] buffer = new char[4096]; + try (Reader reader = value.getCharacterStream()) { + int count; + while ((count = reader.read(buffer)) != -1) { + text.append(buffer, 0, count); + } + } + return new WriteCellData<>(text.toString()); + } +} diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/DefaultConverterLoaderTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/DefaultConverterLoaderTest.java index a30708a52..1d646c597 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/DefaultConverterLoaderTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/DefaultConverterLoaderTest.java @@ -19,9 +19,11 @@ package org.apache.fesod.sheet.converters; +import java.sql.Clob; import java.time.LocalTime; import java.util.Map; import org.apache.fesod.sheet.converters.ConverterKeyBuild.ConverterKey; +import org.apache.fesod.sheet.converters.clob.ClobStringConverter; import org.apache.fesod.sheet.converters.localtime.LocalTimeDateConverter; import org.apache.fesod.sheet.converters.localtime.LocalTimeNumberConverter; import org.apache.fesod.sheet.converters.localtime.LocalTimeStringConverter; @@ -67,6 +69,21 @@ void loadConvertersRegistersLocalTimeFamily() { writeConverter.get(ConverterKeyBuild.buildKey(LocalTime.class, CellDataTypeEnum.STRING))); } + @Test + void loadConvertersRegistersClobStringConverter() { + Map> allConverter = DefaultConverterLoader.loadAllConverter(); + Assertions.assertInstanceOf( + ClobStringConverter.class, + allConverter.get(ConverterKeyBuild.buildKey(Clob.class, CellDataTypeEnum.STRING))); + + Map> writeConverter = DefaultConverterLoader.loadDefaultWriteConverter(); + Assertions.assertInstanceOf( + ClobStringConverter.class, writeConverter.get(ConverterKeyBuild.buildKey(Clob.class))); + Assertions.assertInstanceOf( + ClobStringConverter.class, + writeConverter.get(ConverterKeyBuild.buildKey(Clob.class, CellDataTypeEnum.STRING))); + } + private static void assertLoadIsImmutableAndCopyIsMutable( Map> loaded, Map> copy) { Map.Entry> entry = diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/clob/ClobStringConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/clob/ClobStringConverterTest.java new file mode 100644 index 000000000..c734a7209 --- /dev/null +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/clob/ClobStringConverterTest.java @@ -0,0 +1,60 @@ +/* + * 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.clob; + +import java.sql.Clob; +import javax.sql.rowset.serial.SerialClob; +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 ClobStringConverterTest { + private static final GlobalConfiguration GLOBAL_CONFIGURATION = new GlobalConfiguration(); + private final ClobStringConverter converter = new ClobStringConverter(); + + @Test + void supportKeys() { + Assertions.assertEquals(Clob.class, converter.supportJavaTypeKey()); + Assertions.assertEquals(CellDataTypeEnum.STRING, converter.supportExcelTypeKey()); + } + + @Test + void convertsCellStringToDetachedClob() throws Exception { + Clob actual = converter.convertToJavaData(new ReadCellData<>("Large text 字符"), null, GLOBAL_CONFIGURATION); + + Assertions.assertEquals("Large text 字符", actual.getSubString(1, (int) actual.length())); + } + + @Test + void convertsClobCharacterStreamToCellString() throws Exception { + Clob value = new SerialClob("Large text 字符".toCharArray()); + + WriteCellData written = converter.convertToExcelData(value, null, GLOBAL_CONFIGURATION); + + Assertions.assertEquals(CellDataTypeEnum.STRING, written.getType()); + Assertions.assertEquals("Large text 字符", written.getStringValue()); + } +}