Go in the JVM? You Gotta Be Kidding… Or Do You? My Accidental Deep Dive into Go, Java, WASM, C# and a Whole Lot of “🤯”

Hey folks! 👋 Your friendly neighborhood SRE here, back with a story that started as a late-night joke and ended up blowing my mind. And yes, the title isn’t clickbait – it’s literally about running Go code inside the Java Virtual Machine (and why not, calling it from C# also). Stick with me, it’s wild.

It all started innocently enough. I was chatting with my brilliant computer scientist buddy, Elias, about some tricky library dependencies we were wrestling with in a Java project. Exasperated, I jokingly said, “Haha, wouldn’t it be hilarious if we could just… you know… run that Go library we need directly in Java? Imagine the chaos!”

Elias, always up for a good tech rabbit hole, just chuckled and said, “Yeah, in our dreams! Java and Go are like oil and water, right?” We laughed it off, moved on to debugging… but the seed was planted.

Later that night, that silly “joke” kept nagging at me. “Go in Java… impossible, right?” my brain reasoned. But then that little voice in the back of my head whispered, “But is it? Didn’t I hear something about… WASM… GraalVM… polyglot…?”

And that, my friends, is how I tumbled headfirst into a weekend-long experiment that left me buzzing with excitement and a newfound appreciation for the magic happening in the world of cross-language compatibility.

The “Impossible” Experiment: Go, WASM, and Java Getting Cozy

Remember that joke? Well, I decided to see just how far down the “impossible” rabbit hole I could go. My initial hunch revolved around WebAssembly (WASM) and GraalVM’s Polyglot capabilities. Here’s the (simplified) mental leap I took:

Could it be…? Could I actually compile Go code to WASM, and then have Elias try to run that WASM module in a Java app using GraalVM? It sounded… insane. And utterly brilliant if it worked.

From Zero to “Hello from Go in Java!” (and a LOT of learning in between)

Let me tell you, setting this up wasn’t exactly a walk in the park – at least, it wouldn’t have been just a few weeks ago! Thanks to the recent release of Go 1.24, things became significantly smoother. Seriously, if I’d tried this just two weeks prior, I probably would have hit a wall of frustration. The Go team has been doing amazing work to streamline the WASI experience.

Following the resources I found (linked at the end of this post, you’ll want to check them out!), I started experimenting with the Go side of things. Here’s the gist of what I did:

  1. Write some Go Code: I started with a super simple Go function – let’s call it hello.go – that just adds two integers and returns the result. Classic “Hello World” level complexity, but perfect for testing the waters.

    package main
    
    import "fmt"
    
    //go:wasmexport Hello
    func Hello() {
       fmt.Println("Hello from the Go side")
    }
    
    func main() {}
    
  2. Compile to WASM (with c-shared): This is where the magic happens. Using Go 1.24, compiling to WASM with the GOOS=wasip1 GOARCH=wasm environment variables and the -buildmode=c-shared flag became surprisingly straightforward. This tells Go to produce a WASM module that exports C-style functions – crucial for interoperability.

    GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o libhello.wasm hello.go
    

With the libhello.wasm file in hand, I passed it over to Elias, excitedly explaining what I had managed to do and suggesting he tackle the Java/GraalVM integration. Being the Java and GraalVM enthusiast he is, he readily jumped in.

And boy, did he deliver! Elias dove into the GraalVM Polyglot API and, after some tinkering together and some trying to get use to polyglot library, we emerged with a Java snippet that was pure magic. (you can delve into some of the blogposts and discussions we had to read to arrive at this conclusion)

package org.example;

import org.graalvm.polyglot.*;
import org.graalvm.polyglot.io.ByteSequence;
import java.io.*;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        byte[] binary = java.nio.file.Files.readAllBytes(Path.of("/home/youruser/project/src/main/resources/libhello.wasm"));

        //We need to set up WASI mode context
        Context.Builder contextBuilder = Context.newBuilder("wasm").option("wasm.Builtins", "wasi_snapshot_preview1");
        Source.Builder sourceBuilder = Source.newBuilder("wasm", ByteSequence.create(binary), "example");
        Source source = sourceBuilder.build();
        Context context = contextBuilder.build();

        // Evaluate the WebAssembly module
        context.eval(source);


        // The WASM resulting from golang needs to be initialized so that the runtime can work properly
        Value initFunction =context.getBindings("wasm").getMember("example").getMember("_initialize");
        Value mainFunction =context.getBindings("wasm").getMember("example").getMember("Hello");

        initFunction.execute();
        mainFunction.execute();
        context.close();
    }
}

BOOM. “Result from Go (WASM) in Java: 12” stared back at us from the console. We actually ran Go code, compiled to WASM, inside a Java application. Our jaws dropped. Joke’s on us, it wasn’t impossible at all!

Beyond “Hello World”: The Real Potential Unveiled

This simple hello function was just the tip of the iceberg. This experiment wasn’t just about a fun tech demo; it opened our eyes to a world of possibilities we hadn’t fully grasped before.

Video Editing in Java? Using FFmpeg-WASI!

To really drive home the point, let’s consider something more practical. Remember FFmpeg, the powerhouse of video and audio processing? There’s a project out there – FFmpeg-WASI – that compiles FFmpeg to WASI!

Think about it: Elias could potentially build a Java-based video editor that leverages the full power of FFmpeg, simply by including the FFmpeg-WASI module and using GraalVM Polyglot! No more wrestling with complex native library integrations, no more platform-specific build headaches. Just WASM modules, ready to be plugged into your Java application. 🤯

C# Joins the Party! WASM Fun with Lizz

The excitement didn’t stop there. The very next day, I was chatting with my friend Lizz, a brilliant C# developer, about this Go-in-Java experiment. Lizz, always eager to explore new tech frontiers, was immediately intrigued. “Think we could do the same thing with C#?” she asked, a mischievous glint in her eye.

Challenge accepted! We quickly discovered that while the C# WASM ecosystem is still evolving, it’s definitely possible to compile C# code to WASM and execute it. Lizz, being the C# guru, took the lead on this one. After some digging and experimenting, she put together this amazing C# code snippet to run a WASM module:

var engine = new Engine();

var module = Module.FromFile(engine, "./libhello.wasm");

using var linker = new Linker(engine);
using var store = new Store(engine);


linker.DefineWasi();

store.SetWasiConfiguration(new WasiConfiguration().WithStandardOutput("hola.txt"));
var instance = linker.Instantiate(store, module);
var memory = instance.GetMemory("memory");

var init = instance.GetAction("_initialize");
var run = instance.GetAction("Hello");

init();
run();

While the specifics of the C# WASM runtime differ from GraalVM, the core principle remains the same: compile code to WASM and then execute it within a compatible environment. Seeing this C# code in action further solidified the potential of WASM and WASI as truly language-agnostic platforms. It wasn’t just about Go and Java anymore; it was about a whole new world of cross-language possibilities opening up!

A “Joke” Turned Revelation

What started as a throwaway joke, a “haha, wouldn’t it be funny…”, turned into a genuine “holy cow, this is actually amazing!” moment, not just once, but twice! This experiment wasn’t just about running Go in Java, or even C# in something else; it was about:

I’m still just scratching the surface, but these weekend experiments have definitely ignited a passion for exploring the possibilities of WASI and cross-language development. It’s clear that we’re entering a new era of software development where language barriers are becoming increasingly blurred.

So, next time someone jokes about something seemingly impossible in tech, maybe, just maybe, take a closer look. You might just stumble upon something truly revolutionary.

Resources I used and highly recommend:

Let me know in the comments what you think! Are you as excited about this as I am? What cool cross-language applications can you imagine building? Let’s discuss! 👇

Creado por Oscar J. Rodriguez B. (2023)