From ff6f6e8d8edd2e15d9fcc385db11e9fff18fb3ae Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 31 Dec 2016 16:41:36 +0100 Subject: [PATCH] bind,cmd,internal: generate reverse bindings for exported Go structs Before this CL, the type of the implicit "this" parameter to Java methods implemented in Go could only be a super class of the generated Java class. For example, the following GoRunnable type is an implementation of the Java interface java.lang.Runnable with a toString method: package somepkg import "Java/java/lang" type GoRunnable struct { lang.Runnable } func (r *GoRunnable) ToString(this lang.Runnable) string { ... } The "this" parameter is implicit in the sense that the reverse generator automatically fills it with a reference to the Java instance of GoRunnable. Note that "this" has the type Java/java/lang.Runnable, not Java/go/somepkg.GoRunnable, which renders it impossible to call Java methods and functions that expect GoRunnable. The most practical example of this is the Android databinding libraries. This CL changes the implicit this parameter to always match the exact type. In the example, the toString implementation becomes: import gopkg "Java/go/somepkg" func (r *GoRunnable) ToString(this gopkg.GoRunnable) string { ... } One strategy would be to simply treat the generated Java classes (GoRunnable in our example) as any other Java class and import it through javap. However, since the Java classes are generated after importing, this present a chicken-and-egg problem. Instead, use the newly added support for structs with embedded prefixed types and synthesize class descriptors for every exported Go struct type. Change-Id: Ic5ce4a151312bd89f91798ed4088c9959225b448 Reviewed-on: https://go-review.googlesource.com/34776 Reviewed-by: David Crawshaw --- bind/bind_test.go | 54 ++-- bind/genclasses.go | 37 ++- bind/genjava.go | 23 +- bind/testdata/classes.go | 3 +- bind/testdata/classes.go.golden | 355 ++++++++++++++++++++++++--- bind/testdata/classes.java.c.golden | 180 ++++++++++++-- bind/testdata/classes.java.h.golden | 9 +- bind/testdata/java.go.golden | 21 -- bind/testdata/java.java.c.golden | 16 -- bind/testdata/java.java.golden | 12 +- bind/testdata/java.java.h.golden | 4 - bind/testpkg/javapkg/classes.go | 11 +- cmd/gobind/gen.go | 4 +- cmd/gobind/main.go | 20 +- cmd/gomobile/bind.go | 20 +- example/reverse/reverse/reverse.go | 3 +- internal/importers/java/java.go | 96 +++++--- internal/importers/java/java_test.go | 2 +- 18 files changed, 674 insertions(+), 196 deletions(-) diff --git a/bind/bind_test.go b/bind/bind_test.go index 73bca05..cf6d009 100644 --- a/bind/bind_test.go +++ b/bind/bind_test.go @@ -223,14 +223,7 @@ func genObjcPackages(t *testing.T, dir string, types []*objc.Named, buf *bytes.B return cg } -func genJavaPackages(t *testing.T, dir string, classes []*java.Class, buf *bytes.Buffer) *ClassGen { - cg := &ClassGen{ - Printer: &Printer{ - IndentEach: []byte("\t"), - Buf: buf, - }, - } - cg.Init(classes) +func genJavaPackages(t *testing.T, dir string, cg *ClassGen) { pkgBase := filepath.Join(dir, "src", "Java") if err := os.MkdirAll(pkgBase, 0700); err != nil { t.Fatal(err) @@ -241,16 +234,16 @@ func genJavaPackages(t *testing.T, dir string, classes []*java.Class, buf *bytes t.Fatal(err) } pkgFile := filepath.Join(pkgDir, "package.go") - buf.Reset() + cg.Buf.Reset() cg.GenPackage(i) - if err := ioutil.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil { + if err := ioutil.WriteFile(pkgFile, cg.Buf.Bytes(), 0600); err != nil { t.Fatal(err) } } - buf.Reset() + cg.Buf.Reset() cg.GenInterfaces() clsFile := filepath.Join(pkgBase, "interfaces.go") - if err := ioutil.WriteFile(clsFile, buf.Bytes(), 0600); err != nil { + if err := ioutil.WriteFile(clsFile, cg.Buf.Bytes(), 0600); err != nil { t.Fatal(err) } @@ -264,7 +257,6 @@ func genJavaPackages(t *testing.T, dir string, classes []*java.Class, buf *bytes if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("failed to go install the generated Java wrappers: %v: %s", err, string(out)) } - return cg } func TestGenJava(t *testing.T) { @@ -274,7 +266,10 @@ func TestGenJava(t *testing.T) { } for _, filename := range allTests { refs := fileRefs(t, filename, "Java/") - classes, err := java.Import("", "", refs) + imp := &java.Importer{ + JavaPkgPrefix: "go.", + } + classes, err := imp.Import(refs) if err != nil { t.Fatal(err) } @@ -287,7 +282,18 @@ func TestGenJava(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpGopath) - cg = genJavaPackages(t, tmpGopath, classes, new(bytes.Buffer)) + cg = &ClassGen{ + Printer: &Printer{ + IndentEach: []byte("\t"), + Buf: new(bytes.Buffer), + }, + } + var genNames []string + for _, emb := range refs.Embedders { + genNames = append(genNames, imp.JavaPkgPrefix+emb.Pkg+"."+emb.Name) + } + cg.Init(classes, genNames) + genJavaPackages(t, tmpGopath, cg) cg.Buf = &buf } pkg := typeCheck(t, filename, tmpGopath) @@ -374,7 +380,10 @@ func TestGenGoJavaWrappers(t *testing.T) { for _, filename := range javaTests { var buf bytes.Buffer refs := fileRefs(t, filename, "Java/") - classes, err := java.Import("", "", refs) + imp := &java.Importer{ + JavaPkgPrefix: "go.", + } + classes, err := imp.Import(refs) if err != nil { t.Fatal(err) } @@ -383,7 +392,18 @@ func TestGenGoJavaWrappers(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpGopath) - cg := genJavaPackages(t, tmpGopath, classes, &buf) + cg := &ClassGen{ + Printer: &Printer{ + IndentEach: []byte("\t"), + Buf: &buf, + }, + } + var genNames []string + for _, emb := range refs.Embedders { + genNames = append(genNames, imp.JavaPkgPrefix+emb.Pkg+"."+emb.Name) + } + cg.Init(classes, genNames) + genJavaPackages(t, tmpGopath, cg) pkg := typeCheck(t, filename, tmpGopath) cg.GenGo() testGenGo(t, filename, &buf, pkg) diff --git a/bind/genclasses.go b/bind/genclasses.go index 409e5eb..c7a144c 100644 --- a/bind/genclasses.go +++ b/bind/genclasses.go @@ -34,6 +34,8 @@ type ( // For each Go package path, the Java class with static functions // or constants. clsPkgs map[string]*java.Class + // supers is the map of classes that need Super methods + supers map[string]struct{} } ) @@ -95,7 +97,14 @@ func (g *ClassGen) goType(t *java.Type, local bool) string { } } -func (g *ClassGen) Init(classes []*java.Class) { +// Init initializes the class wrapper generator. Classes is the +// list of classes to wrap, supers is the list of class names +// that need Super methods. +func (g *ClassGen) Init(classes []*java.Class, supers []string) { + g.supers = make(map[string]struct{}) + for _, s := range supers { + g.supers[s] = struct{}{} + } g.classes = classes g.imported = make(map[string]struct{}) g.typePkgs = make(map[string][]*java.Class) @@ -210,7 +219,7 @@ func (g *ClassGen) GenH() { g.Printf("extern ") g.genCMethodDecl("cproxy", cls.JNIName, f) g.Printf(";\n") - if cls.HasSuper() { + if _, ok := g.supers[cls.Name]; ok { g.Printf("extern ") g.genCMethodDecl("csuper", cls.JNIName, f) g.Printf(";\n") @@ -227,9 +236,15 @@ func (g *ClassGen) GenC() { for _, cls := range g.classes { g.genC(cls) g.Printf("static jclass class_%s;\n", cls.JNIName) + if _, ok := g.supers[cls.Name]; ok { + g.Printf("static jclass sclass_%s;\n", cls.JNIName) + } for _, f := range cls.AllMethods { if g.isFuncSupported(f) { g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName) + if _, ok := g.supers[cls.Name]; ok { + g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName) + } } } } @@ -241,9 +256,16 @@ func (g *ClassGen) GenC() { for _, cls := range g.classes { g.Printf("clazz = (*env)->FindClass(env, %q);\n", strings.Replace(cls.FindName, ".", "/", -1)) g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName) + if _, ok := g.supers[cls.Name]; ok { + g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName) + g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName) + } for _, f := range cls.AllMethods { if g.isFuncSupported(f) { g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc) + if _, ok := g.supers[cls.Name]; ok { + g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc) + } } } } @@ -257,7 +279,7 @@ func (g *ClassGen) GenC() { } g.genCMethodDecl("cproxy", cls.JNIName, f) g.genCMethodBody(cls, f, false) - if cls.HasSuper() { + if _, ok := g.supers[cls.Name]; ok { g.genCMethodDecl("csuper", cls.JNIName, f) g.genCMethodBody(cls, f, true) } @@ -296,9 +318,10 @@ func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) { } g.Printf("Method(env, _this, ") if virtual { - g.Printf("class_%s, ", cls.JNIName) + g.Printf("sclass_%s, sm_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) + } else { + g.Printf("m_%s_%s", cls.JNIName, f.JNIName) } - g.Printf("m_%s_%s", cls.JNIName, f.JNIName) for i := range f.Params { g.Printf(", _a%d", i) } @@ -509,7 +532,7 @@ func (g *ClassGen) genGo(cls *java.Class) { g.Printf(" return p.ToString()\n") g.Printf("}\n") } - if cls.HasSuper() { + if _, ok := g.supers[cls.Name]; ok { g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name)) g.Printf(" return &super_%s{p}\n", cls.JNIName) g.Printf("}\n\n") @@ -693,7 +716,7 @@ func (g *ClassGen) genInterface(cls *java.Class) { g.genFuncDecl(true, f) g.Printf("\n") } - if cls.HasSuper() { + if _, ok := g.supers[cls.Name]; ok { g.Printf("Super() %s\n", goClsName(cls.Name)) } if cls.Throwable { diff --git a/bind/genjava.go b/bind/genjava.go index 780eeb6..bcd0a4c 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -228,21 +228,18 @@ func (g *JavaGen) genStruct(s structInfo) { v := params.At(0) if v.Name() == "this" { t := v.Type() - if isJavaType(t) { - clsName := classNameFor(t) - cls := g.clsMap[clsName] - found := false - for _, sup := range jinf.supers { - if cls == sup { - found = true - break + if t, ok := t.(*types.Named); ok { + obj := t.Obj() + pkg := obj.Pkg() + if pkgFirstElem(pkg) == "Java" { + clsName := classNameFor(t) + exp := g.javaPkgName(g.Pkg) + "." + s.obj.Name() + if clsName != exp { + g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, n, m.Name(), exp) + continue } + hasThis = true } - if !found { - g.errorf("the type %s of the `this` argument to method %s.%s is not a super class to %s", cls.Name, n, m.Name(), n) - continue - } - hasThis = true } } } diff --git a/bind/testdata/classes.go b/bind/testdata/classes.go index 696507e..8e531c0 100644 --- a/bind/testdata/classes.go +++ b/bind/testdata/classes.go @@ -5,6 +5,7 @@ package java import ( + gopkg "Java/go/java" "Java/java/io" "Java/java/lang" "Java/java/util/Spliterators" @@ -15,7 +16,7 @@ type Runnable struct { lang.Runnable } -func (r *Runnable) Run(this lang.Runnable) { +func (r *Runnable) Run(this gopkg.Runnable) { } type InputStream struct { diff --git a/bind/testdata/classes.go.golden b/bind/testdata/classes.go.golden index 2875ff7..fc10f31 100644 --- a/bind/testdata/classes.go.golden +++ b/bind/testdata/classes.go.golden @@ -11,7 +11,6 @@ type Java_lang_Runnable interface { type Java_io_InputStream interface { Read() (int32, error) - Super() Java_io_InputStream } type Java_util_concurrent_Future interface { @@ -20,16 +19,34 @@ type Java_util_concurrent_Future interface { } type Java_lang_Object interface { - Super() Java_lang_Object } type Java_util_concurrent_TimeUnit interface { - Super() Java_util_concurrent_TimeUnit } type Java_util_Spliterators interface { } +type Go_java_Future interface { + Get() (Java_lang_Object, error) + Get2(a0 int64, a1 Java_util_concurrent_TimeUnit) (Java_lang_Object, error) + Super() Go_java_Future +} + +type Go_java_InputStream interface { + Read() (int32, error) + Super() Go_java_InputStream +} + +type Go_java_Object interface { + Super() Go_java_Object +} + +type Go_java_Runnable interface { + Run() + Super() Go_java_Runnable +} + // File is generated by gobind. Do not edit. package gomobile_bind @@ -53,6 +70,10 @@ import "Java/java/util/concurrent/Future" import "Java/java/lang/Object" import "Java/java/util/concurrent/TimeUnit" import "Java/java/util/Spliterators" +import "Java/go/java/Future" +import "Java/go/java/InputStream" +import "Java/go/java/Object" +import "Java/go/java/Runnable" import "unsafe" import "reflect" @@ -75,6 +96,10 @@ func initClasses() { init_java_lang_Object() init_java_util_concurrent_TimeUnit() init_java_util_Spliterators() + init_go_java_Future() + init_go_java_InputStream() + init_go_java_Object() + init_go_java_Runnable() } var class_java_lang_Runnable C.jclass @@ -156,27 +181,6 @@ func (p *proxy_class_java_io_InputStream) Read() (int32, error) { return _res, _exc } -func (p *proxy_class_java_io_InputStream) Super() Java.Java_io_InputStream { - return &super_java_io_InputStream{p} -} - -type super_java_io_InputStream struct {*proxy_class_java_io_InputStream} - -func (p *super_java_io_InputStream) Read() (int32, error) { - res := C.csuper_java_io_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) - _res := int32(res.res) - var _exc error - _exc_ref := _seq.FromRefNum(int32(res.exc)) - if _exc_ref != nil { - if res.exc < 0 { // go object - _exc = _exc_ref.Get().(error) - } else { // foreign object - _exc = (*proxy_error)(_exc_ref) - } - } - return _res, _exc -} - var class_java_util_concurrent_Future C.jclass func init_java_util_concurrent_Future() { @@ -278,12 +282,6 @@ type proxy_class_java_lang_Object _seq.Ref func (p *proxy_class_java_lang_Object) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_lang_Object) Super() Java.Java_lang_Object { - return &super_java_lang_Object{p} -} - -type super_java_lang_Object struct {*proxy_class_java_lang_Object} - var class_java_util_concurrent_TimeUnit C.jclass func init_java_util_concurrent_TimeUnit() { @@ -309,12 +307,6 @@ type proxy_class_java_util_concurrent_TimeUnit _seq.Ref func (p *proxy_class_java_util_concurrent_TimeUnit) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_util_concurrent_TimeUnit) Super() Java.Java_util_concurrent_TimeUnit { - return &super_java_util_concurrent_TimeUnit{p} -} - -type super_java_util_concurrent_TimeUnit struct {*proxy_class_java_util_concurrent_TimeUnit} - var class_java_util_Spliterators C.jclass func init_java_util_Spliterators() { @@ -376,6 +368,290 @@ type proxy_class_java_util_Spliterators _seq.Ref func (p *proxy_class_java_util_Spliterators) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } +var class_go_java_Future C.jclass + +func init_go_java_Future() { + cls := C.CString("go/java/Future") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_go_java_Future = clazz + Future.Cast = func(v interface{}) Java.Go_java_Future { + t := reflect.TypeOf((*proxy_class_go_java_Future)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_go_java_Future) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_go_java_Future) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "go.java.Future")) + } + return cv + } +} + +type proxy_class_go_java_Future _seq.Ref + +func (p *proxy_class_go_java_Future) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_go_java_Future) Get() (Java.Java_lang_Object, error) { + res := C.cproxy_go_java_Future_get__(C.jint(p.Bind_proxy_refnum__())) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +func (p *proxy_class_go_java_Future) Get2(a0 int64, a1 Java.Java_util_concurrent_TimeUnit) (Java.Java_lang_Object, error) { + _a0 := C.jlong(a0) + var _a1 C.jint = _seq.NullRefNum + if a1 != nil { + _a1 = C.jint(_seq.ToRefNum(a1)) + } + res := C.cproxy_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(C.jint(p.Bind_proxy_refnum__()), _a0, _a1) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +func (p *proxy_class_go_java_Future) Super() Java.Go_java_Future { + return &super_go_java_Future{p} +} + +type super_go_java_Future struct {*proxy_class_go_java_Future} + +func (p *super_go_java_Future) Get() (Java.Java_lang_Object, error) { + res := C.csuper_go_java_Future_get__(C.jint(p.Bind_proxy_refnum__())) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +func (p *super_go_java_Future) Get2(a0 int64, a1 Java.Java_util_concurrent_TimeUnit) (Java.Java_lang_Object, error) { + _a0 := C.jlong(a0) + var _a1 C.jint = _seq.NullRefNum + if a1 != nil { + _a1 = C.jint(_seq.ToRefNum(a1)) + } + res := C.csuper_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(C.jint(p.Bind_proxy_refnum__()), _a0, _a1) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +var class_go_java_InputStream C.jclass + +func init_go_java_InputStream() { + cls := C.CString("go/java/InputStream") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_go_java_InputStream = clazz + InputStream.Cast = func(v interface{}) Java.Go_java_InputStream { + t := reflect.TypeOf((*proxy_class_go_java_InputStream)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_go_java_InputStream) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_go_java_InputStream) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "go.java.InputStream")) + } + return cv + } +} + +type proxy_class_go_java_InputStream _seq.Ref + +func (p *proxy_class_go_java_InputStream) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_go_java_InputStream) Read() (int32, error) { + res := C.cproxy_go_java_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +func (p *proxy_class_go_java_InputStream) Super() Java.Go_java_InputStream { + return &super_go_java_InputStream{p} +} + +type super_go_java_InputStream struct {*proxy_class_go_java_InputStream} + +func (p *super_go_java_InputStream) Read() (int32, error) { + res := C.csuper_go_java_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc +} + +var class_go_java_Object C.jclass + +func init_go_java_Object() { + cls := C.CString("go/java/Object") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_go_java_Object = clazz + Object.Cast = func(v interface{}) Java.Go_java_Object { + t := reflect.TypeOf((*proxy_class_go_java_Object)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_go_java_Object) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_go_java_Object) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "go.java.Object")) + } + return cv + } +} + +type proxy_class_go_java_Object _seq.Ref + +func (p *proxy_class_go_java_Object) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_go_java_Object) Super() Java.Go_java_Object { + return &super_go_java_Object{p} +} + +type super_go_java_Object struct {*proxy_class_go_java_Object} + +var class_go_java_Runnable C.jclass + +func init_go_java_Runnable() { + cls := C.CString("go/java/Runnable") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_go_java_Runnable = clazz + Runnable.Cast = func(v interface{}) Java.Go_java_Runnable { + t := reflect.TypeOf((*proxy_class_go_java_Runnable)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_go_java_Runnable) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_go_java_Runnable) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "go.java.Runnable")) + } + return cv + } +} + +type proxy_class_go_java_Runnable _seq.Ref + +func (p *proxy_class_go_java_Runnable) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_go_java_Runnable) Run() { + res := C.cproxy_go_java_Runnable_run(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if (_exc != nil) { panic(_exc) } +} + +func (p *proxy_class_go_java_Runnable) Super() Java.Go_java_Runnable { + return &super_go_java_Runnable{p} +} + +type super_go_java_Runnable struct {*proxy_class_go_java_Runnable} + +func (p *super_go_java_Runnable) Run() { + res := C.csuper_go_java_Runnable_run(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if (_exc != nil) { panic(_exc) } +} + // Package gomobile_bind is an autogenerated binder stub for package java. // gobind -lang=go classes // @@ -392,6 +668,7 @@ package gomobile_bind import "C" import ( + java_1 "Java/go/java" "Java/java/io" "Java/java/lang" "Java/java/util/concurrent" @@ -572,13 +849,13 @@ func proxyjava_Runnable_Runnable_Get(refnum C.int32_t) C.int32_t { func proxyjava_Runnable_Run(refnum C.int32_t, param_this C.int32_t) { ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*java.Runnable) - var _param_this lang.Runnable + var _param_this java_1.Runnable _param_this_ref := _seq.FromRefNum(int32(param_this)) if _param_this_ref != nil { if param_this < 0 { // go object - _param_this = _param_this_ref.Get().(lang.Runnable) + _param_this = _param_this_ref.Get().(java_1.Runnable) } else { // foreign object - _param_this = (*proxy_class_java_lang_Runnable)(_param_this_ref) + _param_this = (*proxy_class_go_java_Runnable)(_param_this_ref) } } v.Run(_param_this) diff --git a/bind/testdata/classes.java.c.golden b/bind/testdata/classes.java.c.golden index 013041d..2e7f7d8 100644 --- a/bind/testdata/classes.java.c.golden +++ b/bind/testdata/classes.java.c.golden @@ -29,9 +29,25 @@ ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024O } static jclass class_java_util_Spliterators; +static jclass class_go_java_Future; +static jclass sclass_go_java_Future; +static jmethodID m_go_java_Future_get__; +static jmethodID sm_go_java_Future_get__; +static jmethodID m_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2; +static jmethodID sm_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2; +static jclass class_go_java_InputStream; +static jclass sclass_go_java_InputStream; +static jmethodID m_go_java_InputStream_read__; +static jmethodID sm_go_java_InputStream_read__; +static jclass class_go_java_Object; +static jclass sclass_go_java_Object; +static jclass class_go_java_Runnable; +static jclass sclass_go_java_Runnable; +static jmethodID m_go_java_Runnable_run; +static jmethodID sm_go_java_Runnable_run; void init_proxies() { - JNIEnv *env = go_seq_push_local_frame(6); + JNIEnv *env = go_seq_push_local_frame(10); jclass clazz; clazz = (*env)->FindClass(env, "java/lang/Runnable"); class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz); @@ -49,6 +65,30 @@ void init_proxies() { class_java_util_concurrent_TimeUnit = (*env)->NewGlobalRef(env, clazz); clazz = (*env)->FindClass(env, "java/util/Spliterators"); class_java_util_Spliterators = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "go/java/Future"); + class_go_java_Future = (*env)->NewGlobalRef(env, clazz); + sclass_go_java_Future = (*env)->GetSuperclass(env, clazz); + sclass_go_java_Future = (*env)->NewGlobalRef(env, sclass_go_java_Future); + m_go_java_Future_get__ = go_seq_get_method_id(clazz, "get", "()Ljava/lang/Object;"); + sm_go_java_Future_get__ = go_seq_get_method_id(sclass_go_java_Future, "get", "()Ljava/lang/Object;"); + m_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2 = go_seq_get_method_id(clazz, "get", "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;"); + sm_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2 = go_seq_get_method_id(sclass_go_java_Future, "get", "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;"); + clazz = (*env)->FindClass(env, "go/java/InputStream"); + class_go_java_InputStream = (*env)->NewGlobalRef(env, clazz); + sclass_go_java_InputStream = (*env)->GetSuperclass(env, clazz); + sclass_go_java_InputStream = (*env)->NewGlobalRef(env, sclass_go_java_InputStream); + m_go_java_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I"); + sm_go_java_InputStream_read__ = go_seq_get_method_id(sclass_go_java_InputStream, "read", "()I"); + clazz = (*env)->FindClass(env, "go/java/Object"); + class_go_java_Object = (*env)->NewGlobalRef(env, clazz); + sclass_go_java_Object = (*env)->GetSuperclass(env, clazz); + sclass_go_java_Object = (*env)->NewGlobalRef(env, sclass_go_java_Object); + clazz = (*env)->FindClass(env, "go/java/Runnable"); + class_go_java_Runnable = (*env)->NewGlobalRef(env, clazz); + sclass_go_java_Runnable = (*env)->GetSuperclass(env, clazz); + sclass_go_java_Runnable = (*env)->NewGlobalRef(env, sclass_go_java_Runnable); + m_go_java_Runnable_run = go_seq_get_method_id(clazz, "run", "()V"); + sm_go_java_Runnable_run = go_seq_get_method_id(sclass_go_java_Runnable, "run", "()V"); go_seq_pop_local_frame(env); } @@ -79,22 +119,6 @@ ret_jint cproxy_java_io_InputStream_read__(jint this) { return __res; } -ret_jint csuper_java_io_InputStream_read__(jint this) { - JNIEnv *env = go_seq_push_local_frame(1); - // Must be a Java object - jobject _this = go_seq_from_refnum(env, this, NULL, NULL); - jint res = (*env)->CallNonvirtualIntMethod(env, _this, class_java_io_InputStream, m_java_io_InputStream_read__); - jobject _exc = go_seq_get_exception(env); - int32_t _exc_ref = go_seq_to_refnum(env, _exc); - if (_exc != NULL) { - res = 0; - } - jint _res = res; - go_seq_pop_local_frame(env); - ret_jint __res = {_res, _exc_ref}; - return __res; -} - ret_jint cproxy_java_util_concurrent_Future_get__(jint this) { JNIEnv *env = go_seq_push_local_frame(1); // Must be a Java object @@ -129,6 +153,128 @@ ret_jint cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit return __res; } +ret_jint cproxy_go_java_Future_get__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_go_java_Future_get__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_go_java_Future_get__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jobject res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_go_java_Future, sm_go_java_Future_get__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1) { + JNIEnv *env = go_seq_push_local_frame(3); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jlong _a0 = a0; + jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1) { + JNIEnv *env = go_seq_push_local_frame(3); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jlong _a0 = a0; + jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL); + jobject res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_go_java_Future, sm_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_go_java_InputStream_read__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jint res = (*env)->CallIntMethod(env, _this, m_go_java_InputStream_read__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_go_java_InputStream_read__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_go_java_InputStream, sm_go_java_InputStream_read__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +jint cproxy_go_java_Runnable_run(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallVoidMethod(env, _this, m_go_java_Runnable_run); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + +jint csuper_go_java_Runnable_run(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallNonvirtualVoidMethod(env, _this, sclass_go_java_Runnable, sm_go_java_Runnable_run); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + // JNI functions for the Go <=> Java bridge. // gobind -lang=java classes // diff --git a/bind/testdata/classes.java.h.golden b/bind/testdata/classes.java.h.golden index 173d7c2..a110ec3 100644 --- a/bind/testdata/classes.java.h.golden +++ b/bind/testdata/classes.java.h.golden @@ -48,9 +48,16 @@ typedef struct ret_nbyteslice { extern jint cproxy_java_lang_Runnable_run(jint this); extern ret_jint cproxy_java_io_InputStream_read__(jint this); -extern ret_jint csuper_java_io_InputStream_read__(jint this); extern ret_jint cproxy_java_util_concurrent_Future_get__(jint this); extern ret_jint cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_jint cproxy_go_java_Future_get__(jint this); +extern ret_jint csuper_go_java_Future_get__(jint this); +extern ret_jint cproxy_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_jint csuper_go_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_jint cproxy_go_java_InputStream_read__(jint this); +extern ret_jint csuper_go_java_InputStream_read__(jint this); +extern jint cproxy_go_java_Runnable_run(jint this); +extern jint csuper_go_java_Runnable_run(jint this); extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jclass clazz, jmethodID m, jint a0); // JNI function headers for the Go <=> Java bridge. // gobind -lang=java classes diff --git a/bind/testdata/java.go.golden b/bind/testdata/java.go.golden index 0ba36a4..d40fa3f 100644 --- a/bind/testdata/java.go.golden +++ b/bind/testdata/java.go.golden @@ -9,7 +9,6 @@ type Java_lang_Float interface { } type Java_lang_Object interface { - Super() Java_lang_Object } type Java_lang_Runnable interface { @@ -19,7 +18,6 @@ type Java_lang_Character interface { } type Java_lang_Character_Subset interface { - Super() Java_lang_Character_Subset } // File is generated by gobind. Do not edit. @@ -117,12 +115,6 @@ type proxy_class_java_lang_Object _seq.Ref func (p *proxy_class_java_lang_Object) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_lang_Object) Super() Java.Java_lang_Object { - return &super_java_lang_Object{p} -} - -type super_java_lang_Object struct {*proxy_class_java_lang_Object} - var class_java_lang_Runnable C.jclass func init_java_lang_Runnable() { @@ -198,12 +190,6 @@ type proxy_class_java_lang_Character_Subset _seq.Ref func (p *proxy_class_java_lang_Character_Subset) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_lang_Character_Subset) Super() Java.Java_lang_Character_Subset { - return &super_java_lang_Character_Subset{p} -} - -type super_java_lang_Character_Subset struct {*proxy_class_java_lang_Character_Subset} - // Package gomobile_bind is an autogenerated binder stub for package java. // gobind -lang=go java // @@ -230,21 +216,14 @@ type proxyjava_F _seq.Ref func (p *proxyjava_F) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -// skipped method O.Super with unsupported parameter or return types - type proxyjava_O _seq.Ref func (p *proxyjava_O) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -// skipped method O.Super with unsupported parameter or result types type proxyjava_R _seq.Ref func (p *proxyjava_R) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -// skipped method S.Super with unsupported parameter or return types - type proxyjava_S _seq.Ref func (p *proxyjava_S) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } - -// skipped method S.Super with unsupported parameter or result types diff --git a/bind/testdata/java.java.c.golden b/bind/testdata/java.java.c.golden index 814478f..26b7f24 100644 --- a/bind/testdata/java.java.c.golden +++ b/bind/testdata/java.java.c.golden @@ -41,14 +41,10 @@ jclass proxy_class_java_F; jmethodID proxy_class_java_F_cons; jclass proxy_class_java_O; jmethodID proxy_class_java_O_cons; -// skipped method O.Super with unsupported parameter or return types - jclass proxy_class_java_R; jmethodID proxy_class_java_R_cons; jclass proxy_class_java_S; jmethodID proxy_class_java_S_cons; -// skipped method S.Super with unsupported parameter or return types - JNIEXPORT void JNICALL Java_go_java_Java__1init(JNIEnv *env, jclass _unused) { @@ -62,8 +58,6 @@ Java_go_java_Java__1init(JNIEnv *env, jclass _unused) { proxy_class_java_O = (*env)->NewGlobalRef(env, clazz); proxy_class_java_O_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); clazz = (*env)->FindClass(env, "go/java/O"); - // skipped method O.Super with unsupported parameter or return types - clazz = (*env)->FindClass(env, "go/java/Java$proxyR"); proxy_class_java_R = (*env)->NewGlobalRef(env, clazz); @@ -74,16 +68,6 @@ Java_go_java_Java__1init(JNIEnv *env, jclass _unused) { proxy_class_java_S = (*env)->NewGlobalRef(env, clazz); proxy_class_java_S_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); clazz = (*env)->FindClass(env, "go/java/S"); - // skipped method S.Super with unsupported parameter or return types - } -// skipped function O.Super with unsupported parameter or return types - -// skipped method O with unsupported parameter or return types - -// skipped function S.Super with unsupported parameter or return types - -// skipped method S with unsupported parameter or return types - diff --git a/bind/testdata/java.java.golden b/bind/testdata/java.java.golden index 74d9694..7a01da8 100644 --- a/bind/testdata/java.java.golden +++ b/bind/testdata/java.java.golden @@ -18,9 +18,7 @@ package go.java; import go.Seq; -public interface O extends F, R { - // skipped method O.Super with unsupported parameter or return types - +public interface O { } @@ -44,9 +42,7 @@ package go.java; import go.Seq; -public interface S extends F, R { - // skipped method S.Super with unsupported parameter or return types - +public interface S { } @@ -94,8 +90,6 @@ public abstract class Java { proxyO(Seq.Ref ref) { this.ref = ref; } - // skipped method O.Super with unsupported parameter or return types - } private static final class proxyR implements Seq.Proxy, R { private final Seq.Ref ref; @@ -120,8 +114,6 @@ public abstract class Java { proxyS(Seq.Ref ref) { this.ref = ref; } - // skipped method S.Super with unsupported parameter or return types - } diff --git a/bind/testdata/java.java.h.golden b/bind/testdata/java.java.h.golden index 03bbe6f..a95fe25 100644 --- a/bind/testdata/java.java.h.golden +++ b/bind/testdata/java.java.h.golden @@ -62,14 +62,10 @@ extern jmethodID proxy_class_java_F_cons; extern jclass proxy_class_java_O; extern jmethodID proxy_class_java_O_cons; -// skipped method O.Super with unsupported parameter or return types - extern jclass proxy_class_java_R; extern jmethodID proxy_class_java_R_cons; extern jclass proxy_class_java_S; extern jmethodID proxy_class_java_S_cons; -// skipped method S.Super with unsupported parameter or return types - #endif diff --git a/bind/testpkg/javapkg/classes.go b/bind/testpkg/javapkg/classes.go index 7043c5f..4c79199 100644 --- a/bind/testpkg/javapkg/classes.go +++ b/bind/testpkg/javapkg/classes.go @@ -7,6 +7,7 @@ package javapkg import ( + gopkg "Java/go/javapkg" "Java/java/beans" "Java/java/io" "Java/java/io/IOException" @@ -34,14 +35,14 @@ type GoRunnable struct { Field string } -func (r *GoRunnable) ToString(this lang.Runnable) string { +func (r *GoRunnable) ToString(this gopkg.GoRunnable) string { return ToStringPrefix } -func (r *GoRunnable) Run(this lang.Runnable) { +func (r *GoRunnable) Run(this gopkg.GoRunnable) { } -func (r *GoRunnable) GetThis(this lang.Runnable) lang.Runnable { +func (r *GoRunnable) GetThis(this gopkg.GoRunnable) lang.Runnable { return this } @@ -86,7 +87,7 @@ type GoObject struct { this lang.Object } -func (o *GoObject) ToString(this lang.Object) string { +func (o *GoObject) ToString(this gopkg.GoObject) string { o.this = this return ToStringPrefix + this.Super().ToString() } @@ -171,7 +172,7 @@ type GoRand struct { util.Random } -func (_ *GoRand) Next(this util.Random, i int32) int32 { +func (_ *GoRand) Next(this gopkg.GoRand, i int32) int32 { return this.Super().Next(i) } diff --git a/cmd/gobind/gen.go b/cmd/gobind/gen.go index 8325b84..b8215d0 100644 --- a/cmd/gobind/gen.go +++ b/cmd/gobind/gen.go @@ -140,7 +140,7 @@ func genPkg(p *types.Package, allPkg []*types.Package, classes []*java.Class) { } } -func genJavaPackages(ctx *build.Context, dir string, classes []*java.Class) error { +func genJavaPackages(ctx *build.Context, dir string, classes []*java.Class, genNames []string) error { var buf bytes.Buffer cg := &bind.ClassGen{ Printer: &bind.Printer{ @@ -148,7 +148,7 @@ func genJavaPackages(ctx *build.Context, dir string, classes []*java.Class) erro Buf: &buf, }, } - cg.Init(classes) + cg.Init(classes, genNames) pkgBase := filepath.Join(dir, "src", "Java") if err := os.MkdirAll(pkgBase, 0700); err != nil { return err diff --git a/cmd/gobind/main.go b/cmd/gobind/main.go index ef6e808..86f02d3 100644 --- a/cmd/gobind/main.go +++ b/cmd/gobind/main.go @@ -60,7 +60,19 @@ func main() { log.Fatal(err) } if len(refs.Refs) > 0 { - classes, err = java.Import(*bootclasspath, *classpath, refs) + pref := *javaPkg + if pref == "" { + pref = "go" + } + if pref != "" { + pref = pref + "." + } + imp := &java.Importer{ + Bootclasspath: *bootclasspath, + Classpath: *classpath, + JavaPkgPrefix: pref, + } + classes, err = imp.Import(refs) if err != nil { log.Fatal(err) } @@ -70,7 +82,11 @@ func main() { log.Fatal(err) } defer os.RemoveAll(tmpGopath) - if err := genJavaPackages(ctx, tmpGopath, classes); err != nil { + var genNames []string + for _, emb := range refs.Embedders { + genNames = append(genNames, pref+emb.Pkg+"."+emb.Name) + } + if err := genJavaPackages(ctx, tmpGopath, classes, genNames); err != nil { log.Fatal(err) } gopath := ctx.GOPATH diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index a3202f7..9bef68a 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -391,7 +391,19 @@ func GenClasses(pkgs []*build.Package, srcDir, jpkgSrc string) ([]*java.Class, e if err != nil { return nil, err } - classes, err := java.Import(bClspath, bindClasspath, refs) + pref := bindJavaPkg + if pref == "" { + pref = "go" + } + if pref != "" { + pref = pref + "." + } + imp := &java.Importer{ + Bootclasspath: bClspath, + Classpath: bindClasspath, + JavaPkgPrefix: pref, + } + classes, err := imp.Import(refs) if err != nil { return nil, err } @@ -402,7 +414,11 @@ func GenClasses(pkgs []*build.Package, srcDir, jpkgSrc string) ([]*java.Class, e Buf: &buf, }, } - g.Init(classes) + var genNames []string + for _, emb := range refs.Embedders { + genNames = append(genNames, pref+emb.Pkg+"."+emb.Name) + } + g.Init(classes, genNames) for i, jpkg := range g.Packages() { pkgDir := filepath.Join(jpkgSrc, "src", "Java", jpkg) if err := os.MkdirAll(pkgDir, 0700); err != nil { diff --git a/example/reverse/reverse/reverse.go b/example/reverse/reverse/reverse.go index c4c3377..a07d834 100644 --- a/example/reverse/reverse/reverse.go +++ b/example/reverse/reverse/reverse.go @@ -9,6 +9,7 @@ import ( "Java/android/databinding/DataBindingUtil" "Java/android/os" "Java/android/support/v7/app" + gopkg "Java/go/reverse" rlayout "Java/go/reverse/R/layout" "Java/go/reverse/databinding/ActivityMainBinding" ) @@ -17,7 +18,7 @@ type MainActivity struct { app.AppCompatActivity } -func (a *MainActivity) OnCreate1(this app.AppCompatActivity, b os.Bundle) { +func (a *MainActivity) OnCreate1(this gopkg.MainActivity, b os.Bundle) { this.Super().OnCreate1(b) db := DataBindingUtil.SetContentView2(this, rlayout.Activity_main) mainBind := ActivityMainBinding.Cast(db) diff --git a/internal/importers/java/java.go b/internal/importers/java/java.go index a84a673..890ec46 100644 --- a/internal/importers/java/java.go +++ b/internal/importers/java/java.go @@ -93,10 +93,13 @@ type Type struct { type TypeKind int -type importer struct { - bootclspath string - clspath string - clsMap map[string]*Class +type Importer struct { + Bootclasspath string + Classpath string + // JavaPkgPrefix is java package name for generated classes. + JavaPkgPrefix string + + clsMap map[string]*Class } const ( @@ -148,11 +151,9 @@ func javapPath() (string, error) { // ... // // } -func Import(bootclasspath, classpath string, refs *importers.References) ([]*Class, error) { - imp := &importer{ - bootclspath: bootclasspath, - clspath: classpath, - clsMap: make(map[string]*Class), +func (j *Importer) Import(refs *importers.References) ([]*Class, error) { + if j.clsMap == nil { + j.clsMap = make(map[string]*Class) } clsSet := make(map[string]struct{}) var names []string @@ -166,19 +167,44 @@ func Import(bootclasspath, classpath string, refs *importers.References) ([]*Cla } } } - classes, err := imp.importClasses(names, true) + classes, err := j.importClasses(names, true) if err != nil { return nil, err } - for _, cls := range classes { - imp.fillAllMethods(cls) + // Embedders refer to every exported Go struct that will have its class + // generated. Allow Go code to reverse bind to those classes by synthesizing + // their class descriptors. + for _, emb := range refs.Embedders { + n := j.JavaPkgPrefix + emb.Pkg + "." + emb.Name + if _, exists := j.clsMap[n]; exists { + continue + } + cls := &Class{ + Name: n, + FindName: n, + JNIName: JNIMangle(n), + PkgName: emb.Name, + } + for _, ref := range emb.Refs { + jpkg := strings.Replace(ref.Pkg, "/", ".", -1) + super := jpkg + "." + ref.Name + if _, exists := j.clsMap[super]; !exists { + return nil, fmt.Errorf("class %q not found", super) + } + cls.Supers = append(cls.Supers, super) + } + classes = append(classes, cls) + j.clsMap[cls.Name] = cls } - imp.fillThrowables() for _, cls := range classes { - imp.mangleOverloads(cls.AllMethods) - imp.mangleOverloads(cls.Funcs) + j.fillAllMethods(cls) } - imp.filterReferences(classes, refs) + j.fillThrowables() + for _, cls := range classes { + j.mangleOverloads(cls.AllMethods) + j.mangleOverloads(cls.Funcs) + } + j.filterReferences(classes, refs) return classes, nil } @@ -211,10 +237,6 @@ func JNIMangle(s string) string { return string(m) } -func (c *Class) HasSuper() bool { - return !c.Final && !c.Interface -} - func (t *Type) Type() string { switch t.Kind { case Int: @@ -316,7 +338,7 @@ func (t *Type) JNICallType() string { } } -func (j *importer) filterReferences(classes []*Class, refs *importers.References) { +func (j *Importer) filterReferences(classes []*Class, refs *importers.References) { refFuncs := make(map[[2]string]struct{}) for _, ref := range refs.Refs { pkgName := strings.Replace(ref.Pkg, "/", ".", -1) @@ -351,16 +373,16 @@ func (j *importer) filterReferences(classes []*Class, refs *importers.References } } -func (j *importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) { +func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) { if len(names) == 0 { return nil, nil } args := []string{"-J-Duser.language=en", "-s", "-protected", "-constants"} - if j.clspath != "" { - args = append(args, "-classpath", j.clspath) + if j.Classpath != "" { + args = append(args, "-classpath", j.Classpath) } - if j.bootclspath != "" { - args = append(args, "-bootclasspath", j.bootclspath) + if j.Bootclasspath != "" { + args = append(args, "-bootclasspath", j.Bootclasspath) } args = append(args, names...) javapPath, err := javapPath() @@ -411,7 +433,7 @@ func (j *importer) importClasses(names []string, allowMissingClasses bool) ([]*C return classes, nil } -func (j *importer) unknownSuperClasses(cls *Class, unk []string) []string { +func (j *Importer) unknownSuperClasses(cls *Class, unk []string) []string { loop: for _, n := range cls.Supers { if s, exists := j.clsMap[n]; exists { @@ -428,7 +450,7 @@ loop: return unk } -func (j *importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { +func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { if !s.Scan() { return nil, fmt.Errorf("%s: missing javap header", name) } @@ -544,7 +566,7 @@ func (j *importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { return cls, nil } -func (j *importer) scanClassDecl(name string, decl string) (*Class, error) { +func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { cls := &Class{ Name: name, } @@ -633,7 +655,7 @@ func (j *importer) scanClassDecl(name string, decl string) (*Class, error) { return nil, fmt.Errorf("missing ending { in class declaration: %q", decl) } -func (j *importer) scanVar(decl, desc string) (*Var, error) { +func (j *Importer) scanVar(decl, desc string) (*Var, error) { v := new(Var) const eq = " = " idx := strings.Index(decl, eq) @@ -664,7 +686,7 @@ func (j *importer) scanVar(decl, desc string) (*Var, error) { return v, nil } -func (j *importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) { +func (j *Importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) { // Member is a method f := new(Func) f.Desc = desc @@ -705,7 +727,7 @@ func (j *importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) { return f, nil } -func (j *importer) fillThrowables() { +func (j *Importer) fillThrowables() { thrCls, ok := j.clsMap["java.lang.Throwable"] if !ok { // If Throwable isn't in the class map @@ -717,7 +739,7 @@ func (j *importer) fillThrowables() { } } -func (j *importer) fillThrowableFor(cls, thrCls *Class) { +func (j *Importer) fillThrowableFor(cls, thrCls *Class) { if cls.Interface || cls.Throwable { return } @@ -729,7 +751,7 @@ func (j *importer) fillThrowableFor(cls, thrCls *Class) { } } -func (j *importer) fillAllMethods(cls *Class) { +func (j *Importer) fillAllMethods(cls *Class) { if len(cls.AllMethods) > 0 { return } @@ -764,7 +786,7 @@ func (j *importer) fillAllMethods(cls *Class) { // mangleOverloads assigns unique names to overloaded Java functions by appending // the argument count. If multiple methods have the same name and argument count, // the method signature is appended in JNI mangled form. -func (j *importer) mangleOverloads(allFuncs []*Func) { +func (j *Importer) mangleOverloads(allFuncs []*Func) { overloads := make(map[string][]*Func) for _, f := range allFuncs { overloads[f.Name] = append(overloads[f.Name], f) @@ -795,7 +817,7 @@ func (j *importer) mangleOverloads(allFuncs []*Func) { } } -func (j *importer) parseJavaValue(v string) (string, bool) { +func (j *Importer) parseJavaValue(v string) (string, bool) { v = strings.TrimRight(v, "df") switch v { case "", "NaN", "Infinity", "-Infinity": @@ -810,7 +832,7 @@ func (j *importer) parseJavaValue(v string) (string, bool) { } } -func (j *importer) parseJavaType(desc string) (*Type, int, error) { +func (j *Importer) parseJavaType(desc string) (*Type, int, error) { t := new(Type) var n int if desc == "" { diff --git a/internal/importers/java/java_test.go b/internal/importers/java/java_test.go index 7cd4c86..c970a5a 100644 --- a/internal/importers/java/java_test.go +++ b/internal/importers/java/java_test.go @@ -43,7 +43,7 @@ func TestImport(t *testing.T) { for _, m := range test.methods { refs.Names[m.GoName] = struct{}{} } - classes, err := Import("", "", refs) + classes, err := (&Importer{}).Import(refs) if err != nil { t.Fatal(err) }