eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

As we know, Java and Go are two prominent programming languages, each excelling in different domains. Java is renowned for its portability and extensive ecosystem, while Go is celebrated for its simplicity, performance, and efficient concurrency handling. In certain scenarios, combining the strengths of both languages can lead to more robust and efficient applications.

In this tutorial we’ll explore how to invoke Go functions from Java without writing any C code, utilizing the Java Native Access (JNA) library to bridge the gap between the two languages.

2. Bridging Java and Go with JNA

Traditionally, invoking native code from Java required writing Java Native Interface (JNI) code in C, which adds complexity and overhead. However, with the advent of the Java Native Access (JNA) library, it is possible to call native shared libraries directly from Java without delving into C code. This approach simplifies the integration process and allows developers to harness Go’s capabilities seamlessly within Java applications.

To understand how this integration works, first, we’ll explore the role of the Java Native Access (JNA) library in bridging Java and Go. Specifically, JNA provides a straightforward way to call functions in native shared libraries from Java code. By compiling Go code into a shared library and exporting the necessary functions, Java can interact with Go functions as if they were part of its own ecosystem.

In essence, this process involves writing the Go functions, compiling them into a shared library, and then creating corresponding Java interfaces that map to these functions using JNA.

2. Setting Up the Project

Before diving into the implementation, it is essential to set up the project environment properly. This involves configuring the build tools and dependencies required for the integration.
In our case, we need the following components:

  • Java Development Kit (JDK): For compiling and running Java code.
  • Go Programming Language: For writing and compiling Go code.
  • Java Native Access (JNA) Library: Included as a dependency in the Maven project.
  • Build Tools: Maven for Java and the Go compiler for Go code.

Let’s add the JNA library as a maven dependency:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.15.0</version>
</dependency>

3. Invoking Go Function from Java

To demonstrate the integration of Go functions into a Java application, we’ll create a simple program where Java calls a Go function that prints a message to the console. The implementation involves several key steps: writing the Go function, compiling it into a shared library, and then writing the Java code that uses the Java Native Access (JNA) library to invoke the Go function.

3.1. Building Go Shared Library

First, we need to define the Go code properly. To make a Go function accessible from the shared library, we must export it with C linkage. This is achieved by including the import “C” statement and placing the //export directive before the function definition. Additionally, an empty main function is required when building a shared library in Go.

Let’s create a file called hello.go:

package main

/*
#include <stdlib.h>
*/
import "C"
import "fmt"

//export SayHello
func SayHello() {
    fmt.Println("Hello Baeldung from Go!")
}

func main() {}

Let’s highlight the most important parts of the code above:

  • The import “C” statement enables CGO, allowing the use of C features and exporting functions.
  • The //export SayHello directive tells the Go compiler to export the SayHello function with C linkage.
  • The empty main function is necessary when compiling the Go code into a shared library.

After writing the Go function, the next step is to compile the Go code into a shared library. This is done using the Go build command with the -buildmode=c-shared option, which produces a shared library file (e.g., libhello.so on Linux or libhello.dll on Windows).

Depending on the operating system we use we need to execute different commands to compile a shared library.

For Linux-based operating systems, we can use the following command:

go build -o libhello.so -buildmode=c-shared hello.go

For Windows, in order to build a dll library, we apply the next command:

go build -o libhello.dll -buildmode=c-shared hello.go

For macOS, to get a dylib library, we execute the corresponding command:

go build -o libhello.dylib -buildmode=c-shared hello.go

As a result, we should find the shared library in our current directory.

For convenience, all these scripts are included in the source code along with the README.md file.

3.2. Creating the JNA Interface

The next step is to proceed to the Java side of the integration. In the Java application, we utilize the Java Native Access (JNA) library to load the shared library and call the Go function. First, we define a Java interface that extends com.sun.jna.Library, declaring the methods corresponding to the exported Go function:

import com.sun.jna.Library;

public interface GoLibrary extends Library {
    void SayHello();
}

In this interface, GoLibrary extends Library, a marker interface from JNA, and the SayHello method signature matches the exported Go function from the shared library.

Next, we write the Java application that uses this interface to load the shared library and invoke the Go function.

import com.sun.jna.Native;

public class HelloGo {
    public static void main(String[] args) {
        GoLibrary goLibrary = Native.load("hello", GoLibrary.class);
        goLibrary.SayHello();
    }
}

In this code, Native.load loads the shared library libhello.so (omitting the lib prefix and .so extension), creates an instance of GoLibrary to access the exported functions, and calls the SayHello method, which invokes the Go function and prints the message to the console.

When running the Java application, it is important to ensure that the shared library is accessible in the library path. This can be achieved by placing the shared library in the same directory as the Java application or by setting the appropriate environment variables:

For Linux-based systems, we define environment variables by calling the export command:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

For Windows, we need to add the directory containing the libhello.dll file to the PATH environment variable. This can be done using the following command in Command Prompt (or permanently through the system environment settings):

set PATH=%PATH%;C:\path\to\directory

For macOS, we use a command similar to Linux:

export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:.

Finally, if everything is setup correctly, we should be able to run our app and get the following output:

Hello Baeldung from Go!

4. Passing Parameters and Returning Values

Building upon the simple example, we can enhance the integration by passing parameters to the Go function and returning values to the Java application. This demonstrates how data can be exchanged between Java and Go.

First, we modify the Go code to include a function that adds two integers and returns the result. In the Go code, we define the AddNumbers function to accept two integers of type C.int and return a C.int.

//export AddNumbers
func AddNumbers(a, b C.int) C.int {
    return a + b
}

After updating the Go code, we need to recompile the shared library to include the new function.

Next, we update the Java interface to include the AddNumbers function. We define an interface corresponding to the Go function, specifying the method signature with appropriate parameters and return types.

public interface GoLibrary extends Library {
    void SayHello();
    int AddNumbers(int a, int b);
}

As a result, we can call the AddNumbers function and pass int parameters:

public static void main(String[] args) {
    GoLibrary goLibrary = Native.load("hello", GoLibrary.class);
    int result = goLibrary.AddNumbers(2, 3);
    System.out.printf("Result is %d%n", result);
}

After running the application we should see the result of the calculation in the output:

Result is 5

5. Handling Complex Data Types

In addition to simple data types, it is often necessary to handle more complex data types, such as strings. To pass a string from Java to Go and receive a string back, we need to handle pointers to C strings in the Go code and map them appropriately in Java.

First, we’ll implement a Go function that accepts a string and returns a greeting message. In the Go code, we define the Greet function, which accepts a *C.char and returns a *C.char. We use C.GoString to convert the C string to a Go string and C.CString to convert the Go string back to a C string.

//export Greet
func Greet(name *C.char) *C.char {
    greeting := fmt.Sprintf("Hello, %s!", C.GoString(name))
    return C.CString(greeting)
}

After adding the new function, we need to recompile the shared library.

Next, we need to update the Java interface to include the Greet function. Since the Go function returns a C string, we’ll use the Pointer class provided by JNA to handle the returned value.

public static void main(String[] args) {
    GoLibrary goLibrary = Native.load("hello", GoLibrary.class);
    Pointer ptr = goLibrary.Greet("Alice");
    String greeting = ptr.getString(0);
    System.out.println(greeting);
    Native.free(Pointer.nativeValue(ptr));
}

In this code, the Greet method is called with the argument “Alice,” the returned Pointer retrieves the string, and Native.free releases the memory allocated by the Go function.

If we run the app, we should probably get the following result:

Hello, Alice!

6. Conclusion

By following the guidelines in this tutorial, we can easily integrate Go functions into a Java application using the Java Native Access (JNA) library without writing any C code. This method combines Go’s performance and concurrency with Java, streamlining integration and speeding up development.

Key factors include ensuring compatibility between Java and Go data types, properly managing memory to avoid leaks, and setting up robust error handling. By combining Java’s ecosystem with Go’s performance optimizations, developers can create efficient and powerful applications.

JNA offers several advantages over JNI, such as eliminating the need for C code, supporting cross-platform development, and simplifying the native integration process for faster implementation.

In conclusion, integrating Go functions into Java using JNA is an effective and straightforward approach that enhances performance while simplifying development.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LS – NPI (cat=Java)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)