Examples
Python Calling Java (log4j)
Use Apache log4j logging library from Python:
from metaffi import MetaFFIRuntime, MetaFFITypes
from metaffi.metaffi_types import new_metaffi_type_info
# Load JVM runtime
runtime = MetaFFIRuntime("openjdk")
# Load log4j JARs
module = runtime.load_module("log4j-api-2.21.1.jar;log4j-core-2.21.1.jar")
# Load LogManager.getLogger(String) -> Logger
getLogger = module.load_entity(
"class=org.apache.logging.log4j.LogManager,callable=getLogger",
[new_metaffi_type_info(MetaFFITypes.metaffi_string8_type)],
[new_metaffi_type_info(MetaFFITypes.metaffi_handle_type,
"org.apache.logging.log4j.Logger")])
# Load Logger.error(String) — instance method
log_error = module.load_entity(
"class=org.apache.logging.log4j.Logger,callable=error,instance_required",
[new_metaffi_type_info(MetaFFITypes.metaffi_handle_type),
new_metaffi_type_info(MetaFFITypes.metaffi_string8_type)],
None)
# Use it
logger = getLogger("pylogger")
log_error(logger, "Logging error from Python!")
runtime.release_runtime_plugin()
Java Calling Go (TestMap)
Use a Go struct with methods from Java. First, compile the Go module:
Go module (TestMap.go):
package main
type TestMap struct {
m map[string]interface{}
Name string
}
func NewTestMap() *TestMap {
return &TestMap{
m: make(map[string]interface{}),
Name: "TestMap Name",
}
}
func (this *TestMap) Set(k string, v interface{}) {
this.m[k] = v
}
func (this *TestMap) Get(k string) interface{} {
return this.m[k]
}
func (this *TestMap) Contains(k string) bool {
_, found := this.m[k]
return found
}
Compile: metaffi -c --idl TestMap.go -g
Java host code:
import metaffi.*;
// Load Go runtime
MetaFFIRuntime runtime = new MetaFFIRuntime("go");
runtime.loadRuntimePlugin();
// Load the compiled Go module
MetaFFIModule module = runtime.loadModule("TestMap_MetaFFIGuest.dll");
// Load NewTestMap() -> handle
Caller newTestMap = module.load("callable=NewTestMap",
null,
new MetaFFITypeInfo[]{ new MetaFFITypeInfo(MetaFFITypes.MetaFFIHandle) });
// Load Set(instance, key, value)
Caller testMapSet = module.load("callable=TestMap.Set,instance_required",
new MetaFFITypeInfo[]{
new MetaFFITypeInfo(MetaFFITypes.MetaFFIHandle),
new MetaFFITypeInfo(MetaFFITypes.MetaFFIString8),
new MetaFFITypeInfo(MetaFFITypes.MetaFFIAny)
}, null);
// Load Contains(instance, key) -> bool
Caller testMapContains = module.load("callable=TestMap.Contains,instance_required",
new MetaFFITypeInfo[]{
new MetaFFITypeInfo(MetaFFITypes.MetaFFIHandle),
new MetaFFITypeInfo(MetaFFITypes.MetaFFIString8)
},
new MetaFFITypeInfo[]{ new MetaFFITypeInfo(MetaFFITypes.MetaFFIBool) });
// Load Get(instance, key) -> any
Caller testMapGet = module.load("callable=TestMap.Get,instance_required",
new MetaFFITypeInfo[]{
new MetaFFITypeInfo(MetaFFITypes.MetaFFIHandle),
new MetaFFITypeInfo(MetaFFITypes.MetaFFIString8)
},
new MetaFFITypeInfo[]{ new MetaFFITypeInfo(MetaFFITypes.MetaFFIAny) });
// Create a TestMap and use it
Object testMap = ((Object[]) newTestMap.call())[0];
testMapSet.call(testMap, "key", Arrays.asList("one", "two", "three"));
Object[] result = (Object[]) testMapGet.call(testMap, "key");
ArrayList<String> list = (ArrayList<String>) result[0];
// list = ["one", "two", "three"]
Go Calling Java
Call a static Java method from Go:
package main
import (
"fmt"
metaffi "github.com/MetaFFI/sdk/api/go"
"github.com/MetaFFI/plugin-sdk/compiler/go/IDL"
)
func main() {
// Load JVM runtime
runtime := metaffi.NewMetaFFIRuntime("openjdk")
runtime.LoadRuntimePlugin()
defer runtime.ReleaseRuntimePlugin()
// Load a Java class
module, _ := runtime.LoadModule("mylib.jar")
// Load a static method: String MyClass.greet(String)
greet, _ := module.Load(
"class=com.example.MyClass,callable=greet",
[]IDL.MetaFFIType{IDL.STRING8},
[]IDL.MetaFFIType{IDL.STRING8})
// Call it
result, _ := greet("World")
fmt.Println(result[0]) // "Hello, World!"
}
Python Calling Go
Call a compiled Go function from Python:
// mathutil.go
package main
func Add(a, b int64) int64 {
return a + b
}
Compile: metaffi -c --idl mathutil.go -g
from metaffi import MetaFFIRuntime, MetaFFITypes
from metaffi.metaffi_types import new_metaffi_type_info
runtime = MetaFFIRuntime("go")
module = runtime.load_module("mathutil_MetaFFIGuest")
add = module.load_entity(
"callable=Add",
[new_metaffi_type_info(MetaFFITypes.metaffi_int64_type),
new_metaffi_type_info(MetaFFITypes.metaffi_int64_type)],
[new_metaffi_type_info(MetaFFITypes.metaffi_int64_type)])
result = add(3, 4)
print(result) # 7
runtime.release_runtime_plugin()
Java Calling Python
Call a Python function from Java:
# calculator.py
def multiply(a, b):
return a * b
import metaffi.*;
MetaFFIRuntime runtime = new MetaFFIRuntime("python3");
runtime.loadRuntimePlugin();
MetaFFIModule module = runtime.loadModule("calculator");
Caller multiply = module.load("callable=multiply",
new MetaFFITypeInfo[]{
new MetaFFITypeInfo(MetaFFITypes.MetaFFIFloat64),
new MetaFFITypeInfo(MetaFFITypes.MetaFFIFloat64)
},
new MetaFFITypeInfo[]{ new MetaFFITypeInfo(MetaFFITypes.MetaFFIFloat64) });
Object[] result = (Object[]) multiply.call(3.0, 4.0);
System.out.println(result[0]); // 12.0
Go Calling Python
Call a Python function from Go:
# greeting.py
def greet(name):
return f"Hello {name} from Python!"
package main
import (
"fmt"
metaffi "github.com/MetaFFI/sdk/api/go"
"github.com/MetaFFI/plugin-sdk/compiler/go/IDL"
)
func main() {
runtime := metaffi.NewMetaFFIRuntime("python3")
runtime.LoadRuntimePlugin()
defer runtime.ReleaseRuntimePlugin()
module, _ := runtime.LoadModule("greeting")
greet, _ := module.Load(
"callable=greet",
[]IDL.MetaFFIType{IDL.STRING8},
[]IDL.MetaFFIType{IDL.STRING8})
result, _ := greet("Go")
fmt.Println(result[0]) // "Hello Go from Python!"
}
Passing Callbacks
You can pass a host-language function as a callback to a foreign module. Wrap it with the MetaFFI callable API:
from metaffi import MetaFFIRuntime
from metaffi.metaffi_types import make_metaffi_callable
def my_callback(value):
print(f"Callback received: {value}")
# Wrap for cross-language use
metaffi_callback = make_metaffi_callable(my_callback)
# Pass metaffi_callback to a foreign function that expects a callable parameter
Working with Objects (instance_required)
When a foreign entity is an instance method or field, use the instance_required tag in the entity path. The object instance is passed as the first parameter:
# Load constructor — returns a handle to the new object
constructor = module.load_entity(
"class=com.example.MyClass,callable=<init>",
None,
[new_metaffi_type_info(MetaFFITypes.metaffi_handle_type)])
# Load instance method — first param is the object handle
get_name = module.load_entity(
"class=com.example.MyClass,callable=getName,instance_required",
[new_metaffi_type_info(MetaFFITypes.metaffi_handle_type)],
[new_metaffi_type_info(MetaFFITypes.metaffi_string8_type)])
obj = constructor()
name = get_name(obj)
See the Entity Path documentation for the full list of keys and tags for each language.