How to invoke user defined non-static Java method from Ballerina

258 Views Asked by At

The example[1] shows how to invoke a Java method. But in my case I need to invoke my own method from my own class. Something like this

Hello.java

public class Hello {
    public String sayHello() {
        return "Hello . . .";
    }
}

hello_java.bal

import ballerina/io;
import ballerina/java;

function sayHelloJava() returns handle = @java:Method {
    name: "sayHello",
    class: "Hello"
} external;


public function main() {
    var txt = sayHelloJava();
    io:println(txt);
}

When I run, I am getting the following exception

Compiling source
        hello_java.bal
error: .::hello_java.bal:4:1: {ballerina/java}CLASS_NOT_FOUND 'Hello'
Running executables

Error: Could not find or load main class ___init

both the .class and the .bal files are in the same directory

can anyone please tell me the correct syntax to invoke the sayHello java method in ballerina.

Also could you explain more about the handle keyword in ballerina

[1] https://ballerina.io/v1-2/learn/by-example/invoke-java-methods.html

2

There are 2 best solutions below

6
On BEST ANSWER

You can refer to the interop guide for a detailed info regarding this.

For your particular case, follow the following steps:

  • Create a Java project for your Hello class and get the built .jar file.
  • Create a new Ballerina project as well and add a module in it (let's say the module is called hello).
  • Create a directory named javalibs in your project root directory and copy the .jar file to it.
  • Your project directory look similar to the following:

    .
    ├── Ballerina.lock
    ├── Ballerina.toml
    ├── javalibs
    │   └── hello-1.0-SNAPSHOT.jar
    └── src
        └── hello
            └── main.bal
    
  • Add the following entries to your Ballerina.toml file:

    [platform]
    target = "java8"
    
       [[platform.libraries]]
       path = "./javalibs/hello-1.0-SNAPSHOT.jar"
       modules = ["hello"]
    
  • Your Ballerina code should look something like the following:

    import ballerina/io;
    import ballerina/java;
    
    public type Hello object {
        public function sayHello() returns string? {
            return java:toString(sayHelloExtern());
        }
    };
    
    function sayHelloExtern() returns handle = @java:Method {
        class: "xyz.pubudu.Hello",
        name: "sayHello",
        paramTypes: []
    } external;
    
    
    public function main() {
        Hello h = new;
        io:println(h.sayHello());
    
        string? s = java:toString(sayHelloExtern());
        io:println(s);
    }
    
  • Now you can run this using ballerina run hello and it should print Hello . . .

With the 1.2.0 release, a new CLI tool called bindgen was introduced to easily generate the Ballerina bindings for Java APIs so the user doesn't have to manually write the bindings as we've done above. Checkout the interop guide I linked to above for more details on it.

1
On

Adding to @pubudu's answer, I just want to show how to invoke a non-static Java method in Ballerina.

Since your sayHello method is a non-static method, you need to create an instance of the Hello class using java:Constructor annotation in ballerina.

Then your sayHello function should take that created instance (the handle value returned from the java:Constructor interop function) as the first parameter.

Your Ballerina code should look like this:

import ballerina/io;
import ballerina/java;

function newHello() returns handle = @java:Constructor {
    class: "Hello"
} external;

function sayHello(handle helloObject) returns handle = @java:Method {
    class: "Hello"
} external;

public function main() {
    var helloObj = newHello();
    io:println(java:toString(sayHello(helloObj)));
}