diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/XlsxEscapeUtils.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/XlsxEscapeUtils.java index 64f42d4ec..6c0ff6fb0 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/XlsxEscapeUtils.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/XlsxEscapeUtils.java @@ -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 @@ -37,11 +38,11 @@ * {@code _x005F_} is the escape for the underscore. Decoding it yields the literal back, not {@code A}. *
* 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 {
diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/write/handler/DefaultWriteHandlerLoader.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/write/handler/DefaultWriteHandlerLoader.java
index 4621e3976..924282ca0 100644
--- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/write/handler/DefaultWriteHandlerLoader.java
+++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/write/handler/DefaultWriteHandlerLoader.java
@@ -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;
@@ -60,6 +61,7 @@ public static List
- * 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.
- *
* 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.
+ *
+ * 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.
@@ -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.
+ *
+ * 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,
diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/readwrite/HexEscapeRoundTripTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/readwrite/HexEscapeRoundTripTest.java
deleted file mode 100644
index fba19522e..000000000
--- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/readwrite/HexEscapeRoundTripTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.readwrite;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import org.apache.fesod.sheet.FesodSheet;
-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.write.handler.EscapeHexCellWriteHandler;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-
-/**
- * Regression test for issue #696: the {@code _xHHHH_}
- * escapes were undone only for cells backed by {@code sharedStrings.xml}, so an inline
- * string - what the default writer emits - reached the caller with the raw escape.
- */
-@Tag(Tags.ROUND_TRIP)
-class HexEscapeRoundTripTest extends AbstractExcelTest {
-
- /**
- * The handler is what puts a real escape in the cell, storing the literal as {@code Product_x005F_x0002_Code}.
- * Taking it from the writer's own output instead would tie the expectation to a writer default, not to the
- * reader under test.
- */
- @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