This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-java.git
The following commit(s) were added to refs/heads/main by this push:
new 53a9ccd8f GH-1300: Use Locale.ROOT when building C Data Interface
format strings (#1301)
53a9ccd8f is described below
commit 53a9ccd8f272bd576ec0524b704c1a1fdab20948
Author: Sotaro Hikita <[email protected]>
AuthorDate: Tue Sep 22 15:40:40 2026 +0900
GH-1300: Use Locale.ROOT when building C Data Interface format strings
(#1301)
`Format.asString` built the `FixedSizeList` (`+w:%d`), `FixedSizeBinary`
(`w:%d`) and `Decimal` (`d:%d,%d[,%d]`) format strings with
`String.format` and no explicit `Locale`. `java.util.Formatter`
localises the digits of `%d` with the default locale, so a JVM running
under `ar-EG`, `bn-BD`, `mr-IN` and similar locales exported `+w:٨`
instead of `+w:8`, which arrow-rs and other implementations reject.
This passes `Locale.ROOT` to the four calls and adds
`FormatTest.testAsStringIgnoresDefaultLocale`, which sets the default
locale to `ar-EG` for the duration of the test and asserts the ASCII
output.
Closes #1300.
---
c/src/main/java/org/apache/arrow/c/Format.java | 8 ++++----
c/src/test/java/org/apache/arrow/c/FormatTest.java | 17 +++++++++++++++++
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/c/src/main/java/org/apache/arrow/c/Format.java
b/c/src/main/java/org/apache/arrow/c/Format.java
index 7ce99614d..7f546fca2 100644
--- a/c/src/main/java/org/apache/arrow/c/Format.java
+++ b/c/src/main/java/org/apache/arrow/c/Format.java
@@ -63,10 +63,10 @@ final class Format {
{
ArrowType.Decimal type = (ArrowType.Decimal) arrowType;
if (type.getBitWidth() == 128) {
- return String.format("d:%d,%d", type.getPrecision(),
type.getScale());
+ return String.format(Locale.ROOT, "d:%d,%d", type.getPrecision(),
type.getScale());
}
return String.format(
- "d:%d,%d,%d", type.getPrecision(), type.getScale(),
type.getBitWidth());
+ Locale.ROOT, "d:%d,%d,%d", type.getPrecision(), type.getScale(),
type.getBitWidth());
}
case Duration:
{
@@ -88,12 +88,12 @@ final class Format {
case FixedSizeBinary:
{
ArrowType.FixedSizeBinary type = (ArrowType.FixedSizeBinary)
arrowType;
- return String.format("w:%d", type.getByteWidth());
+ return String.format(Locale.ROOT, "w:%d", type.getByteWidth());
}
case FixedSizeList:
{
ArrowType.FixedSizeList type = (ArrowType.FixedSizeList) arrowType;
- return String.format("+w:%d", type.getListSize());
+ return String.format(Locale.ROOT, "+w:%d", type.getListSize());
}
case FloatingPoint:
{
diff --git a/c/src/test/java/org/apache/arrow/c/FormatTest.java
b/c/src/test/java/org/apache/arrow/c/FormatTest.java
index c77332433..3691ca095 100644
--- a/c/src/test/java/org/apache/arrow/c/FormatTest.java
+++ b/c/src/test/java/org/apache/arrow/c/FormatTest.java
@@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Locale;
import org.apache.arrow.vector.types.DateUnit;
import org.apache.arrow.vector.types.FloatingPointPrecision;
import org.apache.arrow.vector.types.IntervalUnit;
@@ -156,4 +157,20 @@ public class FormatTest {
assertThrows(UnsupportedOperationException.class, () -> Format.asType(":",
0L));
assertThrows(NumberFormatException.class, () -> Format.asType("w:1,2,3",
0L));
}
+
+ @Test
+ public void testAsStringIgnoresDefaultLocale() {
+ // Locales that use digits other than 0-9 (Arabic-Indic, Bengali,
Devanagari, ...)
+ // must not leak into the format string, which other implementations parse
as ASCII.
+ Locale saved = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.forLanguageTag("ar-EG"));
+ assertEquals("d:10,2", Format.asString(new ArrowType.Decimal(10, 2,
128)));
+ assertEquals("d:10,2,256", Format.asString(new ArrowType.Decimal(10, 2,
256)));
+ assertEquals("w:16", Format.asString(new ArrowType.FixedSizeBinary(16)));
+ assertEquals("+w:8", Format.asString(new ArrowType.FixedSizeList(8)));
+ } finally {
+ Locale.setDefault(saved);
+ }
+ }
}