Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions docs/source/java/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <java-install-maven-testing>`.

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
Expand Down Expand Up @@ -76,7 +88,7 @@ plugin. This plugin generates useful platform-dependent properties
such as ``os.detected.name`` and ``os.detected.arch`` needed to resolve
transitive dependencies of Flight.

.. code-block::
.. code-block:: xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
Expand Down Expand Up @@ -107,9 +119,11 @@ transitive dependencies of Flight.
</build>
</project>

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

<build>
<plugins>
Expand All @@ -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.
54 changes: 54 additions & 0 deletions java/memory/memory-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,58 @@
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

<configuration>
<excludes>
<!-- Test is only useful when NOT running with add-opens -->
<exclude>**/TestOpens.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>opens-tests</id>
<!-- Run tests WITHOUT add-opens to make sure we fail-fast -->
<activation>
<jdk>[16,]</jdk>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to get the TestOpens exception with JRE18 but if finished without that error, Is there some additional configuration needed? Probably mvn -Dtest="TestOpens" clean test not thrown that exception because for test this inherit parent configuration.

[ERROR] Failures: 
[ERROR]   TestOpens.testMemoryUtilFailsLoudly:32 Expected java.lang.Throwable to be thrown, but nothing was thrown.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works with just mvn test. I presume specifying the test name manually is causing it to bypass this configuration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, that was the case

</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

<executions>
<execution>
<id>opens-tests</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<!-- Dummy value to stop inheriting the default add-opens flag -->
<argLine>-Dfoo=bar</argLine>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could suggest that this line add more arg configuration instead of reset inheriting .values...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean parent project configure maven-surefire-plugin to add <argLine>--add-opens=java.base/java.nio=ALL-UNNAMED</argLine>, if the plan is to TestOpens.java fail will be needed to reset Surefire parent configuration

When you run the TestOpens test it's throw the exception?

<excludes>
<!-- Need something (anything) here to make Maven not inherit the value above -->
<exclude>**/TestArrowBuf.java</exclude>
</excludes>
<includes>
<include>**/TestOpens.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
}
}