java-plugin is a client-side implementation of
go-plugin. You can use it to run
plugins written in Go (or any language, but Go is best supported) from a JVM application.
Let's say you have a Java (or Kotlin, or Groovy) interface. You'd like to be
able to implement that interface in Go rather than in a JVM language. You can use java-plugin!
Imagine your interface is a simple Counter:
interface Counter {
fun put(key: String, value: Long, adder: (a: Long, b: Long) -> Long)
fun get(key: String): Long
}When put-ing a new value with a Counter, you can pass an adder lambda
implementation that maps the old value into a new value to be stored.
If you have a binary that implements this interface, you can fetch a Counter like so:
val manager = Manager()
val client = manager.start(
ClientConfig(
handshakeConfig = HandshakeConfig(
magicCookieKey = "key",
magicCookieValue = "value",
protocolVersion = 1
),
cmd = listOf("./path/to/plugin/binary"),
plugins = listOf(CounterPlugin())
)
)
// This Counter looks like a normal Java interface!
val counter = client.dispense<Counter>()
counter.put("key", 10) { a, b ->
println("adding $a + $b")
a + b
}For more implementation guidance, see the Examples.
java-plugin implements many of go-plugin's features:
- Bidirectional communication
- Complex arguments and return values
- Protocol versioning
- Logging and stdout/stderr syncing
- Automatic mTLS
java-plugin supports plugins communicating via gRPC over Unix domain sockets. It
does not support Go's net/rpc protocol or communication over localhost.
java-plugin is tested on macos-latest and ubuntu-latest.
The *-example directories contain complete, runnable plugin examples. Be sure to clone this
repo with its submodules:
git clone git@github.com:danielpeach/java-plugin.git --recurse-submodulesIf you're trying to run the examples from Intellij, please remember to run the buildGo gradle task
beforehand.
Automatic mTLS does not work for plugins using bidirectional communication. This is a bug in the server-side framework.