Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.fesod.sheet.write.handler.impl.EscapeHexCellWriteHandler;

/**
* The {@code _xHHHH_} escapes that xlsx uses for characters XML 1.0 forbids, defined by section 3.18.9 of the Office
Expand All @@ -37,11 +38,11 @@
* {@code _x005F_} is the escape for the underscore. Decoding it yields the literal back, not {@code A}.
* <p>
* The write half of the same convention lives in
* {@link org.apache.fesod.sheet.write.handler.EscapeHexCellWriteHandler EscapeHexCellWriteHandler}, which produces
* {@link EscapeHexCellWriteHandler EscapeHexCellWriteHandler}, which produces
* that {@code _x005F_x} form. Both sides read {@code _xHHHH_} the same way, so a change to what counts as an escape
* belongs in both.
*
* @see org.apache.fesod.sheet.write.handler.EscapeHexCellWriteHandler
* @see EscapeHexCellWriteHandler
*/
public class XlsxEscapeUtils {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.fesod.sheet.support.ExcelTypeEnum;
import org.apache.fesod.sheet.write.handler.impl.DefaultRowWriteHandler;
import org.apache.fesod.sheet.write.handler.impl.DimensionWorkbookWriteHandler;
import org.apache.fesod.sheet.write.handler.impl.EscapeHexCellWriteHandler;
import org.apache.fesod.sheet.write.handler.impl.FillStyleCellWriteHandler;
import org.apache.fesod.sheet.write.handler.impl.WriteSheetWorkbookWriteHandler;
import org.apache.fesod.sheet.write.style.DefaultStyle;
Expand Down Expand Up @@ -60,6 +61,7 @@ public static List<WriteHandler> loadDefaultHandler(Boolean useDefaultStyle, Exc
case XLSX:
handlerList.add(new DimensionWorkbookWriteHandler());
handlerList.add(new DefaultRowWriteHandler());
handlerList.add(new EscapeHexCellWriteHandler());
handlerList.add(new FillStyleCellWriteHandler());
handlerList.add(new WriteSheetWorkbookWriteHandler());
if (useDefaultStyle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
* under the License.
*/

package org.apache.fesod.sheet.write.handler;
package org.apache.fesod.sheet.write.handler.impl;

import org.apache.fesod.sheet.enums.CellDataTypeEnum;
import org.apache.fesod.sheet.event.NotRepeatExecutor;
import org.apache.fesod.sheet.metadata.Head;
import org.apache.fesod.sheet.metadata.data.WriteCellData;
import org.apache.fesod.sheet.write.handler.CellWriteHandler;
import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder;
import org.apache.fesod.sheet.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
Expand All @@ -36,18 +38,18 @@
* To store the literal _xHHHH_ sequence without it being decoded by POI, we need to escape the initial underscore by
* replacing _x with _x005F_x.
* <p>
* This handler is not registered by default. Without it the writer stores {@code _xHHHH_}-shaped text exactly as
* typed, and any reader that follows the convention - Fesod, POI or Excel - decodes it back to the character it
* names, so the literal does not survive a round trip. Register it on the write to keep such text intact.
* <p>
* The read half of the same convention lives in
* {@link org.apache.fesod.sheet.util.XlsxEscapeUtils#utfDecode(String) XlsxEscapeUtils.utfDecode}, which undoes what
* this handler writes. Both sides read {@code _xHHHH_} the same way, so a change to what counts as an escape belongs
* in both.
* <p>
* This handler implements {@link NotRepeatExecutor} so that it is only executed once. {@link #uniqueValue()} returns
* the fully qualified class name, which never collides with handlers from other classes even across different class
* loaders.
*
* @see org.apache.fesod.sheet.util.XlsxEscapeUtils#utfDecode(String)
*/
public class EscapeHexCellWriteHandler implements CellWriteHandler {
public class EscapeHexCellWriteHandler implements CellWriteHandler, NotRepeatExecutor {

// ASCII hex digits only. Not Character.digit(c, 16), which also accepts non-ASCII
// digits such as U+0663 that OOXML never uses.
Expand All @@ -64,6 +66,17 @@ public class EscapeHexCellWriteHandler implements CellWriteHandler {
private static final int PREFIX_LENGTH = PREFIX.length();
private static final int HEX_DIGIT_COUNT = 4;

/**
* Returns the fully qualified class name as the unique identity of this handler.
* <p>
* This handler only needs to execute once. The fully qualified class name serves as the unique identity,
* which never collides with handlers from other classes even across different class loaders.
*/
@Override
public String uniqueValue() {
return this.getClass().getName();
}

@Override
public void afterCellDataConverted(
WriteSheetHolder writeSheetHolder,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@
import org.apache.fesod.sheet.testkit.Tags;
import org.apache.fesod.sheet.testkit.base.AbstractExcelTest;
import org.apache.fesod.sheet.testkit.enums.ExcelFormat;
import org.apache.fesod.sheet.testkit.listeners.CollectingReadListener;
import org.apache.fesod.sheet.testkit.models.SimpleData;
import org.apache.fesod.sheet.testkit.params.ExcelFormatSource;
import org.apache.fesod.sheet.write.handler.impl.EscapeHexCellWriteHandler;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;

@Tag(Tags.ROUND_TRIP)
Expand All @@ -49,8 +53,8 @@ private File writeEscapedWorkbook(ExcelFormat format) throws IOException {

FesodSheet.write(file)
.excelType(format.toExcelTypeEnum())
.head(Collections.singletonList(Collections.singletonList("value")))
.registerWriteHandler(new EscapeHexCellWriteHandler())
.head(Collections.singletonList(Collections.singletonList("value")))
.sheet("escape")
.doWrite(rows);
return file;
Expand Down Expand Up @@ -81,4 +85,22 @@ void registeredOnAWrite_keepsLiteralHexSequencesIntactAcrossFormats(ExcelFormat
File file = writeEscapedWorkbook(format);
Assertions.assertEquals("_xB9f0_ and _x1234_", readBackFirstDataValue(file, format));
}

@Test
void escapedOnWrite_readsBackAsTheLiteral() throws IOException {
SimpleData data = new SimpleData();
data.setName("Product_x0002_Code");
File file = createTempFile("hex-escape", ExcelFormat.XLSX);
FesodSheet.write(file, SimpleData.class)
.registerWriteHandler(new EscapeHexCellWriteHandler())
.sheet()
.doWrite(Collections.singletonList(data));

CollectingReadListener<SimpleData> listener = new CollectingReadListener<>();
FesodSheet.read(file, SimpleData.class, listener).sheet().doRead();
List<SimpleData> rows = listener.getRows();

Assertions.assertEquals(1, rows.size());
Assertions.assertEquals("Product_x0002_Code", rows.get(0).getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.fesod.sheet.enums.CellDataTypeEnum;
import org.apache.fesod.sheet.metadata.data.WriteCellData;
import org.apache.fesod.sheet.testkit.Tags;
import org.apache.fesod.sheet.write.handler.impl.EscapeHexCellWriteHandler;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.junit.jupiter.api.Assertions;
Expand Down
Loading