Compare commits

9 Commits
trunk ... main

Author SHA1 Message Date
idk
1f518ab27f use GetName instead of getName 2022-01-04 18:10:15 -05:00
idk
e0caf138a0 more logging 2022-01-04 17:42:44 -05:00
idk
61f30dd25c Get rid of separate generate cmd. 2022-01-04 14:57:05 -05:00
idk
174c183f31 add modules 2022-01-04 13:41:43 -05:00
idk
3d0c812790 Reflect working changes in README.md 2021-11-11 22:02:20 -05:00
idk
7e3907d19d Reflect working changes in README.md 2021-11-11 21:57:26 -05:00
idk
35f49e85ec README.md 2021-11-11 14:44:22 -05:00
idk
5541c5a726 Merge branch 'trunk' into 'main'
Initial commit, Proof-of-Concept

See merge request idk/clientapp!1
2021-11-11 03:20:48 +00:00
idk
f4fd2050fa Initial commit 2021-11-11 03:17:25 +00:00
21 changed files with 115 additions and 27 deletions

View File

@@ -2,8 +2,16 @@
export CLASSPATH="app.jar:$(HOME)/i2p/lib/*:$()/java/net/i2p/ExampleClientApp/*"
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
GOPATH:=$(HOME)/go
all: package jar check
fixvendor:
mkdir -p $(GOPATH)/pkg/mod/github.com/sridharv/gojava/
cp $(GOPATH)/src/github.com/sridharv/gojava/LoadJNI.java $(GOPATH)/pkg/mod/github.com/sridharv/gojava/LoadJNI.java
package: fmt
gojava -v -o app.jar build . #i2pgit.org/idk/clientapp
gojava -v -o app.jar build i2pgit.org/idk/clientapp
fmt:
gofmt -w -s *.go
@@ -15,5 +23,3 @@ check:
jar:
rm -rf java && mkdir java
javac -classpath "app.jar:$(HOME)/i2p/lib/*" -d java *.java

68
README.md Normal file
View File

@@ -0,0 +1,68 @@
# clientapp
Code generation tools for creating for-real ClientApp's using Go/JNI. Currently
just a usable POC, if you're doing everything right it works perfectly and
it's reasonably simple. In the future, the goal is foolproof and automatic.
Credit: https://github.com/sridharv/gojava for figuring out how to hack
`gomobile bind` and enable this technique.
Usage: First, adapt your application so that it can be controlled by the I2P
ClientAppManager by implementing this interface:
``` Go
type ClientApp interface {
GetDisplayName() string
GetName() string
GetState() ClientAppState
GetClientState() int
StartupClient()
Shutdown()
}
```
in your Go application. Once you have done that, import the library:
``` Go
import "i2pgit.org/idk/clientapp"
```
and call `clientapp.GenerateJava(&ExampleClientApp)` during your code generation
phase to generate the `.java` wrapper. This small script will work:
``` Go
//go:build generate
// +build generate
package main
import (
"io/ioutil"
. "i2pgit.org/idk/clientapp"
)
func main() {
ioutil.WriteFile(ClientAppName()+".java", []byte(GenerateJava(&ExampleClientApp{})), 0644)
}
```
Which you can call by adding the a `go generate` to your source file:
``` Go
//go:generate go run --tags=generate i2pgit.org/idk/clientapp/cmd
```
Build your application and generate any `.jar` files for your Go library using
`go build` or `gojava build` first. Then, run `go generate`. You should end up
with a file named `ExampleClientApp.java` in the build directory. The hard part's
over.
Copy the `.jar` file containing your JNI bindings and your Go library to your
classpath. Then, copy the generated `.java` file to the desired location in your
codebase. Now you can use your Go ClientApp from Java with real state tracking,
you can call Go functions from Java and with a little more effort, call Java
functions from Go.
Likely application: Yggdrasil plugin. IPFS plugin. Syndie plugin. VPN plugin?
Syncthing plugin? Really a ton of stuff.

BIN
app.jar

Binary file not shown.

View File

@@ -2,12 +2,18 @@ package clientapp
import (
"fmt"
"io/ioutil"
"log"
"reflect"
"strings"
// "path/filepath"
)
//go:generate go run --tags=generate i2pgit.org/idk/clientapp/cmd
//go:generate go test
func Generator() error {
return ioutil.WriteFile(basicClientApp.GetName()+".java", []byte(GenerateJava(basicClientApp)), 0644)
}
// ClientAppState shadows ClientAppState from Java. In go there are no enums,
// only enum types instead, so this requires a function to convert it, which
@@ -53,11 +59,17 @@ type ExampleClientApp struct {
// GetDisplayName() implements ClientApp in Java and in Go
func (e *ExampleClientApp) GetDisplayName() string {
if e.DisplayName == "" {
return e.GetName()
}
return e.DisplayName
}
// GetName() implements ClientApp in Java and in Go
func (e *ExampleClientApp) GetName() string {
if e.Name == "" {
return "ExampleClientApp"
}
return e.Name
}
@@ -87,18 +99,22 @@ var basicClientApp ClientApp = &ExampleClientApp{}
// clientAppImpl is used by libraries that implement the ClientApp interface.
// Set ClientAppImpl = an instance of your struct in order to emit a Java file
// with a wrapper class to accompany your generated `.jar` file.
var ClientAppImpl interface{} = &ExampleClientApp{}
//var ClientAppImpl interface{} = &ExampleClientApp{}
func GenerateJava() string {
func GenerateJava(ClientAppImpl interface{}) string {
var ECA string = strings.Split(reflect.TypeOf(ClientAppImpl).String(), ".")[len(strings.Split(reflect.TypeOf(ClientAppImpl).String(), "."))-1]
// var CECA string = reflect.TypeOf(ExampleClientApp{}).String()
var pkgdeclaration string = fmt.Sprintf("\npackage net.i2p.%s;\n", ECA)
var importdeclaration string = "import net.i2p.app.ClientApp;\nimport net.i2p.app.ClientAppState;\n"
var declaration string = fmt.Sprintf("public class %s implements ClientApp {\n", ECA)
var innerdeclaration string = fmt.Sprintf("\tgo.%s.%s.%s _clientApp;\n", ClientPkgName(), ClientPkgJavaName(), ClientAppName())
elem1 := ClientPkgName(ClientAppImpl)
elem2 := ClientPkgJavaName(ClientAppImpl)
elem3 := ClientAppName(ClientAppImpl)
log.Printf("%s %s %s", elem1, elem2, elem3)
var innerdeclaration string = fmt.Sprintf("\tgo.%s.%s.%s _clientApp;\n", elem1, elem2, elem3)
var overrideDisplayName string = "\t@Override\n\tpublic String getDisplayName() {\n\t\treturn _clientApp.getDisplayName();\n\t}\n"
var overrideName string = "\t@Override\n\tpublic String getName() {\n\t\treturn _clientApp.getName();\n\t}\n"
var overrideName string = "\t@Override\n\tpublic String GetName() {\n\t\treturn _clientApp.getName();\n\t}\n"
var convertClientState string = ` private ClientAppState convertClientState(long cas){
switch((int)cas){
case 0:
@@ -140,15 +156,17 @@ func GenerateJava() string {
closerdeclaration
}
func ClientAppName() string {
var CA string = strings.Split(reflect.TypeOf(ExampleClientApp{}).String(), ".")[len(strings.Split(reflect.TypeOf(ExampleClientApp{}).String(), "."))-1]
return CA
func ClientAppName(clientAppImpl interface{}) string {
var CA string = strings.Split(reflect.TypeOf(clientAppImpl).String(), ".")[len(strings.Split(reflect.TypeOf(clientAppImpl).String(), "."))-1]
return strings.Replace(CA, "*", "", -1)
}
func ClientPkgJavaName() string {
return strings.Title(strings.ToLower(strings.Split(reflect.TypeOf(ExampleClientApp{}).String(), ".")[0]))
func ClientPkgJavaName(clientAppImpl interface{}) string {
TC := strings.Title(strings.ToLower(strings.Split(reflect.TypeOf(clientAppImpl).String(), ".")[0]))
return strings.Replace(TC, "*", "", -1)
}
func ClientPkgName() string {
return strings.Split(reflect.TypeOf(ExampleClientApp{}).String(), ".")[0]
func ClientPkgName(clientAppImpl interface{}) string {
PN := strings.Split(reflect.TypeOf(clientAppImpl).String(), ".")[0]
return strings.Replace(PN, "*", "", -1)
}

View File

@@ -3,5 +3,5 @@ package clientapp
import "testing"
func TestJavaOutput(t *testing.T) {
t.Log(GenerateJava())
t.Log(Generator())
}

View File

@@ -1,11 +0,0 @@
//go:build generate
// +build generate
package main
import "io/ioutil"
import . "i2pgit.org/idk/clientapp"
func main() {
ioutil.WriteFile(ClientAppName()+".java",[]byte(GenerateJava()), 0644)
}

5
go.mod Normal file
View File

@@ -0,0 +1,5 @@
module i2pgit.org/idk/clientapp
go 1.17
require github.com/sridharv/gomobile-java v0.0.0-20160328180427-34d2814361d9 // indirect

2
go.sum Normal file
View File

@@ -0,0 +1,2 @@
github.com/sridharv/gomobile-java v0.0.0-20160328180427-34d2814361d9 h1:CxtEo+hway5QMC0/orvahh/wI4PLxpqSfa3LcPUzTHc=
github.com/sridharv/gomobile-java v0.0.0-20160328180427-34d2814361d9/go.mod h1:AS6xm8lC0q4pJwq3IkCYnQFj1MKCEEdJc5Qa/CVTmn8=

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.