Call a User-Defined Java Method from Ballerina
This article was written using Ballerina Swan Lake Update 8 (2201.8.0) and Java JDK 17.
Due to Java’s widespread adoption as a programming language, it owns a richer set of libraries compared to those available for Ballerina in Ballerina Central. To leverage the functionality of these Java libraries within Ballerina, Ballerina provides a mechanism to execute Java code and retrieve the output via external functions. Essentially, an external function in Ballerina is a function where its body is associated with a corresponding Java method.
Let’s take a simple scenario where Ballerina consumes some utility functions from a user-defined Java library.
Step 1: Create a Java Library
Let’s create a Java library called Utilities
. This library will contain a package named com.utils
, which contains two classes named IntUtils.java.
and StringUtils.java
.
└── src
└── com
└── utils
├── IntUtils.java
└── StringUtils.java
The IntUtils.java
class contains a simple add
function, which adds two numbers and returns the result.
package com.utils;
public class IntUtils {
public static int add(int a, int b) {
return a + b;
}
}
The StringUtils.java
class contains a replace
function, which replaces oldChar
with newChar
in the given source
text.
package com.utils;
public class StringUtils {
public static String replace(String source, char oldChar, char newChar) {
return source.replace(oldChar, newChar);
}
}
Step 2: Create the Ballerina Project
Create a new Ballerina project by executing bal new FFI
. This will create a new Ballerina project with the name FFI
.
├── Ballerina.toml
├── Dependencies.toml
└── main.bal
Step 3: Add the Utilities Library as a Dependency
You can do this in two ways.
- Add as a dependency JAR file
- Add as a Maven dependency
We are going to follow the first way, therefore, let’s create the JAR file for the Utilities
library.
Note: For instructions on creating a JAR file, refer to this short video.
Next, create a folder called libs/java
and put the Utilities.jar
there.
├── Ballerina.toml
├── Dependencies.toml
├── libs
│ └── java
│ └── Utilities.jar
└── main.bal
Now, you need to tell Ballerina to use this JAR as a dependency. To do that, let’s add the following to the Ballerina.toml
file.
[[platform.java17.dependency]]
path = "./libs/java/Utilities.jar"
Note: You can place the JAR files anywhere in the project and provide the path from the source root.
Step 4: Implement the External Functions
4.1. Implement the External Function for the add
Method
Let’s implement the Ballerina external function to invoke the add
method in IntUtil.java
.
function add(int a, int b) returns int = @java:Method {
'class: "com.utils.IntUtils"
} external;
Here, to mark that this function maps to a Java method, we use the @java:Method{}
annotation with the external
keyword. The ‘class
field is a required field that specifies the class in which the method exists. This will now look for a static
Java method named add
with two int
parameters in IntUtils.java
.
Note: If the Java method name that we intend to call is different from the Ballerina method name, we can use the
name
field in the annotation to specify the Java method name.
We can now call the Ballerina function and print the result.
4.2. Implement the External Function for the replace
Method
The first parameter of the Java replace
function is String
, which should be mapped to the handle
type in Ballerina. The second and third parameters are of the Java primitive type char
, which will be mapped to the Ballerina type int
. Therefore, the Ballerina external function signature would be, replace(handle, int, int) returns handle
.
The above program is written to replace the underscore with white spaces in a given text. We can create the handle
value, which refers to the Java String
value using the java:fromString()
method. Next, pass the corresponding ASCII values to the underscore and white space, which are 95
and 32
, respectively. Executing this program will print cats and dogs
.
That’s it. Now, you have successfully called Java functions from the Ballerina side. However, when it comes to large libraries, it is not practical to write all of these manually. This is where the Ballerina Bindgen tool comes in handy. This will auto-generate all the necessary Ballerina classes and functions for you.
Also, take a look at the Ballerina FFI learn page, where you can find out how to call instance methods, how to deal with overloaded constructors and methods, map Java classes into Ballerina classes, handle Java exceptions, etc.
That’s all for now. Stay tuned for the next article!.