The Bindgen Tool

The Bindgen Tool is a CLI tool that generates Ballerina bindings for Java classes.

The following sections explain how the Bindgen Tool works.

The bindgen command

ParameterDescriptionType
(-cp|--classpath) <classpath>...This optional parameter could be used to specify one or more comma-delimited classpaths for retrieving the Java libraries required for the generation of the Ballerina bindings. The classpath could be provided as comma-separated paths of JAR files or as comma-separated paths of directories containing all the relevant Java libraries. If the Ballerina bindings are to be generated from a standard Java library, from a library available inside the Ballerina SDK, or a platform library specified in the Ballerina.toml file, then, you need not specify the classpath explicitly.Optional
(-mvn|--maven) <groupId>:<artifactId>:<version>Specifies a Maven dependency required for the generation of the Ballerina bindings. Here, the specified library and its transitive dependencies gets resolved into the target/platform-libs directory of the Ballerina package. If the tool is not executed inside a package or if the output path does not point to a package, the target/platform-libs directory structure gets created in the output path to store the Maven dependencies. The tool updates the Ballerina.toml file with the platform libraries if the command is executed inside a Ballerina package.Optional
(-o|--output) <output>Generates all the bindings inside a single directory instead of generating module-level mappings. This option could be used in instances where all the mappings are required inside a single module. The specified directory doesn't always have to be inside a Ballerina package.Optional
--publicSets the visibility modifier of the generated binding classes to public. This flag is applicable only if the bindings are generated inside a single directory.Mandatory
<class-name>...One or more space-separated fully-qualified Java class names for which the Ballerina bridge code is to be generated. These class names should be provided at the end of the command.Mandatory

Generated bridge code

When the tool is run, a .bal file gets created to represent each Java class. This would contain the respective Ballerina binding class along with the required Java interoperability mappings. By default, these .bal files are generated inside separate modules representing each Java package. If the [(-o|--output) <output-path>] option is used, they are generated inside a single directory.

Apart from creating bindings for the specified Java classes, the command also generates empty Ballerina binding classes for dependent Java classes. A Java class would be considered dependent if it is used inside one of the generated Ballerina binding classes.

A set of additional .bal files are generated to store the error types used within the Ballerina binding classes.

The generated bindings are inside the specified output directory as follows.

Java to Ballerina mapping

Java classes

A Java class is mapped to a Ballerina class. This Ballerina class has the same name as the Java class.

E.g., the generated Ballerina class of the java.util.ArrayDeque class is as follows.

If there are multiple classes with the same simple name, they need to be generated using a single execution. The tool then, applies a numerical identifier at the end of duplicated class names. This could be manually changed into something meaningful if required.

The format for specifying inner classes using the command is <package-name>.ClassName$InnerClassName. The dollar sign might have to be escaped using the backslash key.

E.g., the command to generate bindings for java.lang.Character.Subset class is as follows.

When referring to Java code to figure out the imported classes, you should be cautious about the Java classes from the java.lang package since these are not visible as imports in the Java code. However, you need not generate bindings for the java.lang.String class since it is mapped into the Ballerina string type from within the generated Ballerina bindings.

Constructors

Constructors of Java classes are mapped to functions outside the Ballerina class. These function names are comprised of the constructor name prefixed with the new keyword. If there are multiple constructors, they are suffixed with an auto-incremented number.

E.g., generated constructors of the java.util.ArrayDeque class is as follows.

Methods

All public methods are exposed through Ballerina bindings. Instance methods reside inside the Ballerina class and these would take the name of the Java method. However, if there are overloaded methods, a numeric suffix is appended at the end of the name.

E.g., some of the generated instance methods of the java.util.ArrayDeque class is as follows.

Static methods would reside outside the Ballerina class as functions, which take the name of the Java method with the Java simple class name appended at the beginning as a prefix.

E.g., a generated static method randomUUID() of the java.util.UUID class is as follows. Here, the Ballerina equivalent of calling UUID.randomUUID() in Java is UUID_randomUUID().

Fields

All public fields of a Java class are exposed through Ballerina bindings in the form of getters and setters. Instance fields have the respective getter and setter methods inside the Ballerina class, whereas, the static fields have getter and setter functions outside the Ballerina class.

The getter and setter functions of an instance field take the name of the field prefixed with a get or set at the beginning.

E.g., get<FIELD_NAME>() and set<FIELD_NAME>(<type> arg)

For a static field, the getter and setter (if the field is not final) functions take the name of the field with a get or set prefix along with the Java simple class name appended at the beginning.

E.g., <Class_Name>_get<FIELD_NAME>() and <Class_Name>_set<FIELD_NAME>(<type> arg)

Java exceptions

When generating Ballerina bindings, Java exceptions are mapped onto Ballerina errors. They have identical names as that of the corresponding Java exceptions. Instead of returning a generic error from the Java side, the bindings return a more meaningful error representing the exact Java exception.

E.g., the following IOException is returned from the read() function in the java.io.FileInputStream Ballerina binding class.

Note: If a Java exception class is explicitly generated as a Ballerina binding class, it would follow the naming convention JException or JError. For instance, the binding class's name for java.io.FileNotFoundException would be JFileNotFoundException.

Dependent classes

When there are dependent Java classes present inside generated Ballerina bindings (as parameters or return types), the Bindgen Tool generates an empty Ballerina binding class to represent each one of these classes. This represents a Java class mapping without the constructors, methods, or field bindings. If one of these classes is required later, the Bindgen Tool could be re-run to generate the complete implementation of the Ballerina bindings.

E.g., the generated dependent class representing java.util.List is as follows.

Type mappings

Generated Ballerina bindings support the following type mappings between Java and Ballerina.

  • Ballerina primitive - Java primitive
  • Ballerina string type - Java String class
  • Ballerina binding class - Java class

The Ballerina binding classes store a handle reference of the Java object using its jObj field.

The following table summarizes how Java primitive types are mapped to the corresponding Ballerina primitive types. This is applicable when mapping a return type of a Java method to a Ballerina type.

Java typeBallerina type
booleanboolean
bytebyte
int, short, char, longint
float, doublefloat

Support for Java subtyping

Ballerina bindings provide support for Java subtyping with the aid of type inclusions in the language.

E.g., a Ballerina binding class mapping the java.io.FileInputStream Java class could be assigned to a Ballerina binding class mapping the java.io.InputStream as follows.

Support for Java casting

The ballerina/jballerina.java module of the Ballerina standard library provides the cast function to support Java casting. This could be used to cast Ballerina binding classes into their subtypes based on assignability.

E.g., a Ballerina binding class instance mapping the java.io.InputStream Java class inputStream could be cast onto a Ballerina binding class mapping the java.io.FileInputStream Java class as follows.