Skip to main content

Java Bindings

The Java bindings are distributed as a JAR targeting Java 8. Native libraries for multiple platforms are embedded in the JAR's resources directory. The correct native library will automatically load during static initialization. These native libraries wrap the underlying C API with a thin layer of JNI.

Shared libraries for the following platforms are included in the release JAR:

  • Windows x64 (Windows 7+)
  • Windows x86 (Windows 7+)
  • Linux x64 (kernel 2.6.32+, glibc 2.11+)
  • Linux AArch64 (kernel 4.2, glibc 2.17+)
  • MacOS x64 (MacOS 10.7+, Lion+)
danger

MacOS x64 libraries are included in the package but are not officially supported. They are useful for developers using MacOS, but are not supported in production.

tip

It is also possible to use an external library by specifying its path in the DNP3_NATIVE_LIB_LOCATION environment variable. This feature can be useful if your platform is not officially supported and you built the bindings manually.

Maven

Release artifacts are published to Maven central. Add this dependency to incorporate them into your projects:

<dependency>
<groupId>io.stepfunc</groupId>
<artifactId>dnp3</artifactId>
<version>${dnp3.version}</version>
</dependency>

Dependencies

In addition to the Rust dependencies, the Java bindings depend on one open source project:

  • joou-java-6 - Apache 2.0 - Java Object Oriented Unsigned (JOOU) integer classes

This library is not distributed by Step Function I/O directly. It is only declared as a dependency for the package manager to retrieve.

Unsigned Integers

Java doesn't support unsigned integers as part of the core language. Instead, the Java code generator uses classes from the JOOU library. This ensures that numeric types crossing the Java/JNI boundary are pre-validated within the correct range. User code that creates unsigned integers will need to import symbols from the JOOU library.

It is particularly helpful to statically import the factory methods on Unsigned class:

import static org.joou.Unsigned.*;
import org.joou.UShort;

This lets you create instances of the unsigned classes:

UShort value = ushort(65535);

Mapping

Java is an object-oriented language that supports all the abstract patterns modeled in the code generator. This section describes those mappings.

Errors

C API errors are transformed into exceptions containing the error enum. The exception class inherits from RuntimeException.

danger

Uncaught exceptions thrown in callbacks will terminate the program. Always wrap your callback logic using try/catch syntax if there's a possibility the callback will throw.

Iterators

Iterators are transformed into List<T> by the code generator. This means that the collections returned by callbacks may be used outside the callback. For example, you can send them to another thread for processing.

Structs

Native structs are mapped to Java classes. They have public member visibility, and the constructor ensures that all values without a reasonable default are initialized. Each field has a with<FieldName> method that sets the field and returns the struct for chaining operations.

Classes

Abstract classes are also mapped to Java classes. They have a private pointer to the underlying native resource. There are two types of generated classes in Java:

  • Generated classes that only have a finalize method: These are automatically garbage collected, while native resources are deallocated in the class's finalize method. These types of classes are typically builder objects such as Commands, Request, and AddressFilter.
  • Generated classes that also provide a public Shutdown method to proactively release native resources: These represent long-lived resources such as Runtime, Master, or TCPServer. They map to an asynchronous Rust task executing on the Tokio runtime. The Shutdown method lets you precisely control when the resource/task will stop.

Asynchronous Methods

Abstract asynchronous methods are transformed into methods that return CompletionStage<T>. You can then chain and use the object in an asynchronous workflow, or transform it into a CompletableFuture<T> and call get().