This is an automated email from the ASF dual-hosted git repository.
jbonofre 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 394755bc6 GH-1007: fix: does not break class loading if direct buffer
allocator is not available (#1008)
394755bc6 is described below
commit 394755bc612f9457446396e4374f2871bbc99d9d
Author: Issac Garcia <[email protected]>
AuthorDate: Thu Feb 26 13:20:01 2026 +0100
GH-1007: fix: does not break class loading if direct buffer allocator is
not available (#1008)
## What's Changed
The Direct Buffer is not always needed to use Arrow memory, however, we
cannot load MemoryUtil class if we don't set:
```
--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED
```
Which is not always needed/possible.
This fix proposes to catch the `InaccessibleObjectException` to not
avoiding the load of the class.
The directBuffer is, in any case not available and a
`UnsupportedOperationException` will be throw as it is in the existing
code
Closes #1007 .
---
.../org/apache/arrow/memory/util/MemoryUtil.java | 23 +++++++++++++++++++---
.../java/org/apache/arrow/memory/TestOpens.java | 17 ++++++----------
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git
a/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java
b/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java
index 91bd7cd90..be0749a21 100644
---
a/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java
+++
b/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java
@@ -18,6 +18,7 @@ package org.apache.arrow.memory.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -81,9 +82,18 @@ public class MemoryUtil {
BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
// get the offset of the address field in a java.nio.Buffer object
+ long maybeOffset;
Field addressField = java.nio.Buffer.class.getDeclaredField("address");
- addressField.setAccessible(true);
- BYTE_BUFFER_ADDRESS_OFFSET = UNSAFE.objectFieldOffset(addressField);
+ try {
+ addressField.setAccessible(true);
+ maybeOffset = UNSAFE.objectFieldOffset(addressField);
+ } catch (InaccessibleObjectException e) {
+ maybeOffset = -1;
+ logger.debug(
+ "Cannot access the address field of java.nio.Buffer. DirectBuffer
operations wont be available",
+ e);
+ }
+ BYTE_BUFFER_ADDRESS_OFFSET = maybeOffset;
Constructor<?> directBufferConstructor;
long address = -1;
@@ -109,6 +119,9 @@ public class MemoryUtil {
} catch (SecurityException e) {
logger.debug("Cannot get constructor for direct buffer
allocation", e);
return e;
+ } catch (InaccessibleObjectException e) {
+ logger.debug("Cannot get constructor for direct buffer
allocation", e);
+ return e;
}
}
});
@@ -156,7 +169,11 @@ public class MemoryUtil {
* @return address of the underlying memory.
*/
public static long getByteBufferAddress(ByteBuffer buf) {
- return UNSAFE.getLong(buf, BYTE_BUFFER_ADDRESS_OFFSET);
+ if (BYTE_BUFFER_ADDRESS_OFFSET != -1) {
+ return UNSAFE.getLong(buf, BYTE_BUFFER_ADDRESS_OFFSET);
+ }
+ throw new UnsupportedOperationException(
+ "Byte buffer address cannot be obtained because sun.misc.Unsafe or
java.nio.DirectByteBuffer.<init>(long, int) is not available");
}
private MemoryUtil() {}
diff --git
a/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java
b/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java
index b5e0a71e7..f74bf63f8 100644
--- a/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java
+++ b/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java
@@ -20,32 +20,27 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.condition.JRE.JAVA_16;
+import org.apache.arrow.memory.util.MemoryUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
public class TestOpens {
- /** Instantiating the RootAllocator should poke MemoryUtil and fail. */
+ /** Accessing MemoryUtil.directBuffer should fail as add-opens is not
configured. */
@Test
@EnabledForJreRange(min = JAVA_16)
public void testMemoryUtilFailsLoudly() {
// This test is configured by Maven to run WITHOUT add-opens. So this
should fail on JDK16+
// (where JEP396 means that add-opens is required to access JDK internals).
// The test will likely fail in your IDE if it doesn't correctly pick this
up.
- Throwable e =
- assertThrows(
- Throwable.class,
- () -> {
- BufferAllocator allocator = new RootAllocator();
- allocator.close();
- });
+ Throwable e = assertThrows(Throwable.class, () ->
MemoryUtil.directBuffer(0, 10));
boolean found = false;
while (e != null) {
- e = e.getCause();
- if (e instanceof RuntimeException
- && e.getMessage().contains("Failed to initialize MemoryUtil")) {
+ if (e instanceof UnsupportedOperationException
+ && e.getMessage().contains("java.nio.DirectByteBuffer.<init>(long,
int) not available")) {
found = true;
break;
}
+ e = e.getCause();
}
assertTrue(found, "Expected exception was not thrown");
}