diff --git a/docs/source/java/install.rst b/docs/source/java/install.rst index 9eaf2b588341..b0ae9e19c690 100644 --- a/docs/source/java/install.rst +++ b/docs/source/java/install.rst @@ -15,36 +15,48 @@ .. specific language governing permissions and limitations .. under the License. +======================= Installing Java Modules ======================= .. contents:: System Compatibility --------------------- +==================== Java modules are regularly built and tested on macOS and Linux distributions. Java Compatibility ------------------- +================== -Java modules are currently compatible with JDK 8, 9, 10, 11, 17, and 18. +Java modules are compatible with JDK 8 and above. Currently, JDK 8, 11, 17, and 18 are tested in CI. When using Java 9 or later, some JDK internals must be exposed by -adding ``--add-opens=java.base/java.nio=ALL-UNNAMED``. Otherwise, -you may see errors like ``module java.base does not "opens +adding ``--add-opens=java.base/java.nio=ALL-UNNAMED`` to the ``java`` command: + +.. code-block:: shell + + # Directly on the command line + $ java --add-opens=java.base/java.nio=ALL-UNNAMED -jar ... + # Indirectly via environment variables + $ env _JAVA_OPTIONS="--add-opens=java.base/java.nio=ALL-UNNAMED" java -jar ... + +Otherwise, you may see errors like ``module java.base does not "opens java.nio" to unnamed module``. +If using Maven and Surefire for unit testing, :ref:`this argument must +be added to Surefire as well `. + Installing from Maven ---------------------- +===================== By default, Maven will download from the central repository: https://repo.maven.apache.org/maven2/org/apache/arrow/ Configure your pom.xml with the Java modules needed, for example: arrow-vector, and arrow-memory-netty. -.. code-block:: +.. code-block:: xml -The ``--add-opens`` flag can be added when running unit tests through Maven: +.. _java-install-maven-testing: -.. code-block:: +The ``--add-opens`` flag must be added when running unit tests through Maven: + +.. code-block:: xml @@ -131,6 +145,14 @@ Or they can be added via environment variable, for example when executing your c _JAVA_OPTIONS="--add-opens=java.base/java.nio=ALL-UNNAMED" mvn exec:java -Dexec.mainClass="YourMainCode" Installing from Source ----------------------- +====================== See :ref:`java-development`. + +IDE Configuration +================= + +Generally, no additional configuration should be needed. However, +ensure your Maven or other build configuration has the ``--add-opens`` +flag as described above, so that the IDE picks it up and runs tests +with that flag as well. diff --git a/java/memory/memory-core/pom.xml b/java/memory/memory-core/pom.xml index 073a20470c2a..e95a270b1539 100644 --- a/java/memory/memory-core/pom.xml +++ b/java/memory/memory-core/pom.xml @@ -37,4 +37,58 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + **/TestOpens.java + + + + + + + + + opens-tests + + + [16,] + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + opens-tests + test + + test + + + + -Dfoo=bar + + + **/TestArrowBuf.java + + + **/TestOpens.java + + + + + + + + + diff --git a/java/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java b/java/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java index c48ee66c2cc5..70e1a2586f2e 100644 --- a/java/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java +++ b/java/memory/memory-core/src/main/java/org/apache/arrow/memory/util/MemoryUtil.java @@ -135,7 +135,10 @@ public Object run() { } catch (Throwable e) { // This exception will get swallowed, but it's necessary for the static analysis that ensures // the static fields above get initialized - final RuntimeException failure = new RuntimeException("Failed to initialize MemoryUtil", e); + final RuntimeException failure = new RuntimeException( + "Failed to initialize MemoryUtil. Was Java started with " + + "`--add-opens=java.base/java.nio=ALL-UNNAMED`? " + + "(See https://arrow.apache.org/docs/java/install.html)", e); failure.printStackTrace(); throw failure; } diff --git a/java/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java b/java/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java new file mode 100644 index 000000000000..7efc11a08acf --- /dev/null +++ b/java/memory/memory-core/src/test/java/org/apache/arrow/memory/TestOpens.java @@ -0,0 +1,46 @@ +/* + * 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.arrow.memory; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.Test; + +public class TestOpens { + /** Instantiating the RootAllocator should poke MemoryUtil and fail. */ + @Test + 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(); + }); + boolean found = false; + while (e != null) { + e = e.getCause(); + if (e instanceof RuntimeException && e.getMessage().contains("Failed to initialize MemoryUtil")) { + found = true; + break; + } + } + assertTrue(found, "Expected exception as not thrown"); + } +}