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");
   }

Reply via email to