diff --git a/bind/genclasses.go b/bind/genclasses.go index 1833703..4aa903b 100644 --- a/bind/genclasses.go +++ b/bind/genclasses.go @@ -7,6 +7,7 @@ package bind import ( "fmt" "path" + "reflect" "strings" "unicode" "unicode/utf8" @@ -49,6 +50,15 @@ func (g *ClassGen) isSupported(t *java.Type) bool { } } +func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool { + for _, f := range fs.Funcs { + if g.isFuncSupported(f) { + return true + } + } + return false +} + func (g *ClassGen) isFuncSupported(f *java.Func) bool { for _, a := range f.Params { if !g.isSupported(a) { @@ -62,6 +72,11 @@ func (g *ClassGen) isFuncSupported(f *java.Func) bool { } func (g *ClassGen) goType(t *java.Type, local bool) string { + if t == nil { + // interface{} is used for parameters types for overloaded methods + // where no common ancestor type exists. + return "interface{}" + } switch t.Kind { case java.Int: return "int32" @@ -153,13 +168,16 @@ func (g *ClassGen) GenPackage(idx int) { g.Printf("var (\n") g.Indent() // Functions - for _, f := range cls.Funcs { - if !f.Public || !g.isFuncSupported(f) { - continue + loop: + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if f.Public && g.isFuncSupported(f) { + g.Printf("%s func", fs.GoName) + g.genFuncDecl(false, fs) + g.Printf("\n") + continue loop + } } - g.Printf("%s func", f.GoName) - g.genFuncDecl(false, f) - g.Printf("\n") } g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name) g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n") @@ -209,17 +227,19 @@ func (g *ClassGen) GenH() { } g.Printf("\n") for _, cls := range g.classes { - for _, f := range cls.AllMethods { - if !g.isFuncSupported(f) { - continue - } - g.Printf("extern ") - g.genCMethodDecl("cproxy", cls.JNIName, f) - g.Printf(";\n") - if _, ok := g.supers[cls.Name]; ok { + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if !g.isFuncSupported(f) { + continue + } g.Printf("extern ") - g.genCMethodDecl("csuper", cls.JNIName, f) + g.genCMethodDecl("cproxy", cls.JNIName, f) g.Printf(";\n") + if _, ok := g.supers[cls.Name]; ok { + g.Printf("extern ") + g.genCMethodDecl("csuper", cls.JNIName, f) + g.Printf(";\n") + } } } } @@ -235,17 +255,21 @@ func (g *ClassGen) GenC() { if _, ok := g.supers[cls.Name]; ok { g.Printf("static jclass sclass_%s;\n", cls.JNIName) } - for _, f := range cls.Funcs { - if !f.Public || !g.isFuncSupported(f) { - continue + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName) } - g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.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) + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + 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) + } } } } @@ -263,22 +287,26 @@ func (g *ClassGen) GenC() { 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.Funcs { - if !f.Public || !g.isFuncSupported(f) { - continue - } - g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName) - if f.Constructor { - g.Printf("go_seq_get_method_id(clazz, \"\", %q);\n", f.Desc) - } else { - g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc) + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName) + if f.Constructor { + g.Printf("go_seq_get_method_id(clazz, \"\", %q);\n", f.Desc) + } else { + g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc) + } } } - 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) + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + 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) + } } } } @@ -287,15 +315,17 @@ func (g *ClassGen) GenC() { g.Outdent() g.Printf("}\n\n") for _, cls := range g.classes { - for _, f := range cls.AllMethods { - if !g.isFuncSupported(f) { - continue - } - g.genCMethodDecl("cproxy", cls.JNIName, f) - g.genCMethodBody(cls, f, false) - if _, ok := g.supers[cls.Name]; ok { - g.genCMethodDecl("csuper", cls.JNIName, f) - g.genCMethodBody(cls, f, true) + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.genCMethodDecl("cproxy", cls.JNIName, f) + g.genCMethodBody(cls, f, false) + if _, ok := g.supers[cls.Name]; ok { + g.genCMethodDecl("csuper", cls.JNIName, f) + g.genCMethodBody(cls, f, true) + } } } } @@ -365,76 +395,84 @@ func initialUpper(s string) string { return string(unicode.ToUpper(r)) + s[n:] } -func (g *ClassGen) genFuncDecl(local bool, f *java.Func) { +func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) { g.Printf("(") - for i, a := range f.Params { + for i, a := range fs.Params { if i > 0 { g.Printf(", ") } - g.Printf("a%d %s", i, g.goType(a, local)) + g.Printf("a%d ", i) + if i == len(fs.Params)-1 && fs.Variadic { + g.Printf("...") + } + g.Printf(g.goType(a, local)) } g.Printf(")") - if f.Throws != "" { - if f.Ret != nil { - g.Printf(" (%s, error)", g.goType(f.Ret, local)) + if fs.Throws { + if fs.HasRet { + g.Printf(" (%s, error)", g.goType(fs.Ret, local)) } else { g.Printf(" error") } - } else if f.Ret != nil { - g.Printf(" %s", g.goType(f.Ret, local)) + } else if fs.HasRet { + g.Printf(" %s", g.goType(fs.Ret, local)) } } func (g *ClassGen) genC(cls *java.Class) { - for _, f := range cls.Funcs { - if !f.Public || !g.isFuncSupported(f) { - continue + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.genCFuncDecl(cls.JNIName, f) + g.Printf(" {\n") + g.Indent() + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)) + for i, a := range f.Params { + g.genCToJava(fmt.Sprintf("a%d", i), a) + } + if f.Constructor { + g.Printf("jobject res = (*env)->NewObject(env") + } else if f.Ret != nil { + g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType()) + } else { + g.Printf("(*env)->CallStaticVoidMethod(env") + } + g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) + for i := range f.Params { + g.Printf(", _a%d", i) + } + g.Printf(");\n") + g.Printf("jobject _exc = go_seq_get_exception(env);\n") + g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") + if f.Ret != nil { + g.genCRetClear("res", f.Ret, "_exc") + g.genJavaToC("res", f.Ret) + } + g.Printf("go_seq_pop_local_frame(env);\n") + if f.Ret != nil { + g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) + g.Printf("return __res;\n") + } else { + g.Printf("return _exc_ref;\n") + } + g.Outdent() + g.Printf("}\n\n") } - g.genCFuncDecl(cls.JNIName, f) - g.Printf(" {\n") - g.Indent() - g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)) - for i, a := range f.Params { - g.genCToJava(fmt.Sprintf("a%d", i), a) - } - if f.Constructor { - g.Printf("jobject res = (*env)->NewObject(env") - } else if f.Ret != nil { - g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType()) - } else { - g.Printf("(*env)->CallStaticVoidMethod(env") - } - g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) - for i := range f.Params { - g.Printf(", _a%d", i) - } - g.Printf(");\n") - g.Printf("jobject _exc = go_seq_get_exception(env);\n") - g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") - if f.Ret != nil { - g.genCRetClear("res", f.Ret, "_exc") - g.genJavaToC("res", f.Ret) - } - g.Printf("go_seq_pop_local_frame(env);\n") - if f.Ret != nil { - g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) - g.Printf("return __res;\n") - } else { - g.Printf("return _exc_ref;\n") - } - g.Outdent() - g.Printf("}\n\n") } } func (g *ClassGen) genH(cls *java.Class) { - for _, f := range cls.Funcs { - if !f.Public || !g.isFuncSupported(f) { - continue + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("extern ") + g.genCFuncDecl(cls.JNIName, f) + g.Printf(";\n") } - g.Printf("extern ") - g.genCFuncDecl(cls.JNIName, f) - g.Printf(";\n") } } @@ -480,13 +518,20 @@ func (g *ClassGen) genGo(cls *java.Class) { g.Printf(" return\n") g.Printf("}\n") g.Printf("class_%s = clazz\n", cls.JNIName) - for _, f := range cls.Funcs { - if !f.Public || !g.isFuncSupported(f) { + for _, fs := range cls.Funcs { + var supported bool + for _, f := range fs.Funcs { + if f.Public && g.isFuncSupported(f) { + supported = true + break + } + } + if !supported { continue } - g.Printf("%s.%s = func", cls.PkgName, f.GoName) - g.genFuncDecl(false, f) - g.genFuncBody(cls, f, "cproxy_s", true) + g.Printf("%s.%s = func", cls.PkgName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "cproxy_s", true) } g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name)) g.Indent() @@ -503,13 +548,13 @@ func (g *ClassGen) genGo(cls *java.Class) { g.Printf("}\n\n") g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName) g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", cls.JNIName) - for _, f := range cls.AllMethods { - if !g.isFuncSupported(f) { + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { continue } - g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, f.GoName) - g.genFuncDecl(false, f) - g.genFuncBody(cls, f, "cproxy", false) + g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "cproxy", false) } if cls.Throwable { g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName) @@ -521,54 +566,145 @@ func (g *ClassGen) genGo(cls *java.Class) { g.Printf(" return &super_%s{p}\n", cls.JNIName) g.Printf("}\n\n") g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName) - for _, f := range cls.AllMethods { - if !g.isFuncSupported(f) { + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { continue } - g.Printf("func (p *super_%s) %s", cls.JNIName, f.GoName) - g.genFuncDecl(false, f) - g.genFuncBody(cls, f, "csuper", false) + g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "csuper", false) } } } -func (g *ClassGen) genFuncBody(cls *java.Class, f *java.Func, prefix string, static bool) { +// genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically, +// by inspecting the number of arguments (if the FuncSet contains varying parameter counts), +// and their types. +func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) { + maxp := len(fs.Funcs[0].Params) + minp := maxp + // sort the function variants into argument sizes. + buckets := make(map[int][]*java.Func) + for _, f := range fs.Funcs { + n := len(f.Params) + if n < minp { + minp = n + } else if n > maxp { + maxp = n + } + buckets[n] = append(buckets[n], f) + } g.Printf(" {\n") g.Indent() - for i, a := range f.Params { - g.genWrite(fmt.Sprintf("a%d", i), a, modeTransient) + if fs.Variadic { + // Switch over the number of arguments. + g.Printf("switch %d + len(a%d) {\n", minp, minp) } - g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName) - if !static { - g.Printf("C.jint(p.Bind_proxy_refnum__())") - } - for i := range f.Params { - if !static || i > 0 { - g.Printf(", ") + for i := minp; i <= maxp; i++ { + funcs := buckets[i] + if len(funcs) == 0 { + continue + } + if fs.Variadic { + g.Printf("case %d:\n", i) + g.Indent() + } + for _, f := range funcs { + if len(funcs) > 1 { + g.Printf("{\n") + g.Indent() + } + var argNames []string + var preds []string + for i, a := range f.Params { + var ct *java.Type + var argName string + if i >= minp { + argName = fmt.Sprintf("a%d[%d]", minp, i-minp) + ct = fs.Params[minp] + } else { + argName = fmt.Sprintf("a%d", i) + ct = fs.Params[i] + } + if !reflect.DeepEqual(ct, a) { + g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false)) + argName = fmt.Sprintf("_a%d", i) + preds = append(preds, fmt.Sprintf("ok%d", i)) + } + argNames = append(argNames, argName) + } + if len(preds) > 0 { + g.Printf("if %s {\n", strings.Join(preds, " && ")) + g.Indent() + } + for i, a := range f.Params { + g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient) + } + g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName) + if !static { + g.Printf("C.jint(p.Bind_proxy_refnum__())") + } + for i := range f.Params { + if !static || i > 0 { + g.Printf(", ") + } + g.Printf("__a%d", i) + } + g.Printf(")\n") + g.genFuncRet(fs, f) + if len(preds) > 0 { + g.Outdent() + g.Printf("}\n") + } + if len(funcs) > 1 { + g.Outdent() + g.Printf("}\n") + } + } + if fs.Variadic { + g.Outdent() } - g.Printf("_a%d", i) } - g.Printf(")\n") - g.genFuncRet(f) + if fs.Variadic { + g.Printf("}\n") + } + if fs.Variadic || len(fs.Funcs) > 1 { + g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name) + } g.Outdent() g.Printf("}\n\n") } -func (g *ClassGen) genFuncRet(f *java.Func) { +func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func) { if f.Ret != nil { g.genRead("_res", "res.res", f.Ret, modeRetained) g.genRefRead("_exc", "res.exc", "error", "proxy_error", true) } else { g.genRefRead("_exc", "res", "error", "proxy_error", true) } - if f.Throws == "" { + if !fs.Throws { g.Printf("if (_exc != nil) { panic(_exc) }\n") - if f.Ret != nil { - g.Printf("return _res\n") + if fs.HasRet { + if f.Ret != nil { + g.Printf("return _res\n") + } else { + // The variant doesn't return a value, but the common + // signature does. Use nil as a placeholder return value. + g.Printf("return nil\n") + } + } else if fs.Variadic || len(fs.Funcs) > 1 { + // If there are overloaded variants, return here to avoid the fallback + // panic generated in genFuncBody. + g.Printf("return\n") } } else { - if f.Ret != nil { - g.Printf("return _res, _exc\n") + if fs.HasRet { + if f.Ret != nil { + g.Printf("return _res, _exc\n") + } else { + // As above, use a nil placeholder return value. + g.Printf("return nil, _exc\n") + } } else { g.Printf("return _exc\n") } @@ -612,26 +748,26 @@ func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasPr g.Printf("}\n") } -func (g *ClassGen) genWrite(v string, t *java.Type, mode varMode) { +func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) { switch t.Kind { case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double: - g.Printf("_%s := C.%s(%s)\n", v, t.CType(), v) + g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v) case java.Boolean: - g.Printf("_%s := C.jboolean(C.JNI_FALSE)\n", v) + g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst) g.Printf("if %s {\n", v) - g.Printf(" _%s = C.jboolean(C.JNI_TRUE)\n", v) + g.Printf(" %s = C.jboolean(C.JNI_TRUE)\n", dst) g.Printf("}\n") case java.String: - g.Printf("_%s := encodeString(%s)\n", v, v) + g.Printf("%s := encodeString(%s)\n", dst, v) case java.Array: if t.Elem.Kind != java.Byte { panic("unsupported array type") } - g.Printf("_%s := fromSlice(%s, %v)\n", v, v, mode == modeRetained) + g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained) case java.Object: - g.Printf("var _%s C.jint = _seq.NullRefNum\n", v) + g.Printf("var %s C.jint = _seq.NullRefNum\n", dst) g.Printf("if %s != nil {\n", v) - g.Printf(" _%s = C.jint(_seq.ToRefNum(%s))\n", v, v) + g.Printf(" %s = C.jint(_seq.ToRefNum(%s))\n", dst, v) g.Printf("}\n") default: panic("invalid kind") @@ -698,12 +834,12 @@ func (g *ClassGen) genInterface(cls *java.Class) { g.Printf("type %s interface {\n", goClsName(cls.Name)) g.Indent() // Methods - for _, f := range cls.AllMethods { - if !g.isFuncSupported(f) { + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { continue } - g.Printf(f.GoName) - g.genFuncDecl(true, f) + g.Printf(fs.GoName) + g.genFuncDecl(true, fs) g.Printf("\n") } if _, ok := g.supers[cls.Name]; ok { diff --git a/bind/genjava.go b/bind/genjava.go index 3164b77..3080fa1 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -9,6 +9,7 @@ import ( "go/constant" "go/types" "math" + "reflect" "regexp" "strings" @@ -38,7 +39,7 @@ type javaClassInfo struct { extends *java.Class // All Java classes and interfaces this class extends and implements. supers []*java.Class - methods map[string]*java.Func + methods map[string]*java.FuncSet // Does the class need a default no-arg constructor genNoargCon bool } @@ -59,16 +60,21 @@ func (g *JavaGen) Init(classes []*java.Class) { continue } inf := &javaClassInfo{ - methods: make(map[string]*java.Func), + methods: make(map[string]*java.FuncSet), genNoargCon: true, // java.lang.Object has a no-arg constructor } for _, n := range classes { cls := g.clsMap[n] - for _, f := range cls.AllMethods { - if f.Final { - continue + for _, fs := range cls.AllMethods { + hasMeth := false + for _, f := range fs.Funcs { + if !f.Final { + hasMeth = true + } + } + if hasMeth { + inf.methods[fs.GoName] = fs } - inf.methods[f.GoName] = f } inf.supers = append(inf.supers, cls) if !cls.Interface { @@ -96,6 +102,104 @@ func (g *JavaGen) Init(classes []*java.Class) { } } +func (j *javaClassInfo) toJavaType(T types.Type) *java.Type { + switch T := T.(type) { + case *types.Basic: + var kind java.TypeKind + switch T.Kind() { + case types.Bool, types.UntypedBool: + kind = java.Boolean + case types.Uint8: + kind = java.Byte + case types.Int16: + kind = java.Short + case types.Int32, types.UntypedRune: // types.Rune + kind = java.Int + case types.Int64, types.UntypedInt: + kind = java.Long + case types.Float32: + kind = java.Float + case types.Float64, types.UntypedFloat: + kind = java.Double + case types.String, types.UntypedString: + kind = java.String + default: + return nil + } + return &java.Type{Kind: kind} + case *types.Slice: + switch e := T.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}} + } + } + return nil + case *types.Named: + if isJavaType(T) { + return &java.Type{Kind: java.Object, Class: classNameFor(T)} + } + } + return nil +} + +// lookupMethod searches the Java class descriptor for a method +// that matches the Go method. +func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func { + jm := j.methods[m.Name()] + if jm == nil { + // If an exact match is not found, try the method with trailing underscores + // stripped. This way, name clashes can be avoided when overriding multiple + // overloaded methods from Go. + base := strings.TrimRight(m.Name(), "_") + jm = j.methods[base] + if jm == nil { + return nil + } + } + // A name match was found. Now use the parameter and return types to locate + // the correct variant. + sig := m.Type().(*types.Signature) + params := sig.Params() + // Convert Go parameter types to their Java counterparts, if possible. + var jparams []*java.Type + i := 0 + if hasThis { + i = 1 + } + for ; i < params.Len(); i++ { + jparams = append(jparams, j.toJavaType(params.At(i).Type())) + } + var ret *java.Type + var throws bool + if results := sig.Results(); results.Len() > 0 { + ret = j.toJavaType(results.At(0).Type()) + if results.Len() > 1 { + throws = isErrorType(results.At(1).Type()) + } + } +loop: + for _, f := range jm.Funcs { + if len(f.Params) != len(jparams) { + continue + } + if throws != (f.Throws != "") { + continue + } + if !reflect.DeepEqual(ret, f.Ret) { + continue + } + for i, p := range f.Params { + if !reflect.DeepEqual(p, jparams[i]) { + continue loop + } + } + return f + } + return nil +} + // ClassNames returns the list of names of the generated Java classes and interfaces. func (g *JavaGen) ClassNames() []string { var names []string @@ -217,32 +321,11 @@ func (g *JavaGen) genStruct(s structInfo) { var jm *java.Func hasThis := false if jinf != nil { - jm = jinf.methods[m.Name()] + hasThis = g.hasThis(n, m) + jm = jinf.lookupMethod(m, hasThis) if jm != nil { g.Printf("@Override ") } - // Check the implicit this argument, if any - sig := m.Type().(*types.Signature) - params := sig.Params() - if params.Len() > 0 { - v := params.At(0) - if v.Name() == "this" { - t := v.Type() - 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 - } - } - } - } } g.Printf("public native ") g.genFuncSignature(m, jm, hasThis) @@ -259,6 +342,35 @@ func (g *JavaGen) genStruct(s structInfo) { g.Printf("}\n\n") } +// hasThis returns whether a method has an implicit "this" parameter. +func (g *JavaGen) hasThis(sName string, m *types.Func) bool { + sig := m.Type().(*types.Signature) + params := sig.Params() + if params.Len() == 0 { + return false + } + v := params.At(0) + if v.Name() != "this" { + return false + } + t, ok := v.Type().(*types.Named) + if !ok { + return false + } + obj := t.Obj() + pkg := obj.Pkg() + if pkgFirstElem(pkg) != "Java" { + return false + } + clsName := classNameFor(t) + exp := g.javaPkgName(g.Pkg) + "." + sName + if clsName != exp { + g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp) + return false + } + return true +} + func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) { g.Printf("public %s(", n) g.genFuncArgs(f, nil, false) @@ -1386,7 +1498,7 @@ func (g *JavaGen) GenC() error { for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) { var jm *java.Func if jinf != nil { - jm = jinf.methods[m.Name()] + jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m)) } g.genJNIFunc(m, sName, jm, false, jinf != nil) } diff --git a/bind/testdata/classes.go b/bind/testdata/classes.go index 0dead86..7263ac7 100644 --- a/bind/testdata/classes.go +++ b/bind/testdata/classes.go @@ -36,12 +36,13 @@ type Future struct { concurrent.Future } -func (_ *Future) Get() lang.Object { - return nil +func (_ *Future) Get() (lang.Object, error) { + return nil, nil } -func (_ *Future) Get2(_ int64, _ concurrent.TimeUnit) lang.Object { - return nil +// Use a trailing underscore to override multiple overloaded methods. +func (_ *Future) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) { + return nil, nil } type Object struct { @@ -51,7 +52,7 @@ type Object struct { func innerClassTypes() { // java.util.Spliterators.iterator use inner class types // for the return value as well as parameters. - Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2(nil) + Spliterators.Iterator(nil) } func returnType() { diff --git a/bind/testdata/classes.go.golden b/bind/testdata/classes.go.golden index c0c20cd..5690ea6 100644 --- a/bind/testdata/classes.go.golden +++ b/bind/testdata/classes.go.golden @@ -131,7 +131,7 @@ const ( ) var ( - Iterator_Ljava_util_Spliterator_00024OfInt_2 func(a0 Java.Java_util_Spliterator_OfInt) Java.Java_util_PrimitiveIterator_OfInt + Iterator func(a0 Java.Java_util_Spliterator) Java.Java_util_Iterator // Cast takes a proxy for a Java object and converts it to a java.util.Spliterators proxy. // Cast panics if the argument is not a proxy or if the underlying object does // not extend or implement java.util.Spliterators. @@ -147,6 +147,8 @@ import "Java" const _ = Java.Dummy type Spliterators Java.Java_util_Spliterators +type Iterator Java.Java_util_Iterator +type Spliterator Java.Java_util_Spliterator // File is generated by gobind. Do not edit. package System @@ -252,6 +254,53 @@ var ( // File is generated by gobind. Do not edit. +package Iterator + +import "Java" + +const _ = Java.Dummy + +const ( +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Iterator proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Iterator. + Cast func(v interface{}) Java.Java_util_Iterator +) + +// File is generated by gobind. Do not edit. + +package Spliterator + +import "Java" + +const _ = Java.Dummy + +type OfInt Java.Java_util_Spliterator_OfInt +type OfLong Java.Java_util_Spliterator_OfLong +type OfDouble Java.Java_util_Spliterator_OfDouble +const ( + ORDERED = 16 + DISTINCT = 1 + SORTED = 4 + SIZED = 64 + NONNULL = 256 + IMMUTABLE = 1024 + CONCURRENT = 4096 + SUBSIZED = 16384 +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator. + Cast func(v interface{}) Java.Java_util_Spliterator +) + +// File is generated by gobind. Do not edit. + package OfInt import "Java" @@ -277,6 +326,8 @@ import "Java" const _ = Java.Dummy type OfInt Java.Java_util_PrimitiveIterator_OfInt +type OfLong Java.Java_util_PrimitiveIterator_OfLong +type OfDouble Java.Java_util_PrimitiveIterator_OfDouble // File is generated by gobind. Do not edit. package OfInt @@ -297,13 +348,76 @@ var ( // File is generated by gobind. Do not edit. -package Spliterator +package OfLong import "Java" const _ = Java.Dummy -type OfInt Java.Java_util_Spliterator_OfInt +const ( +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.PrimitiveIterator.OfLong proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.PrimitiveIterator.OfLong. + Cast func(v interface{}) Java.Java_util_PrimitiveIterator_OfLong +) + +// File is generated by gobind. Do not edit. + +package OfLong + +import "Java" + +const _ = Java.Dummy + +const ( +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator.OfLong proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator.OfLong. + Cast func(v interface{}) Java.Java_util_Spliterator_OfLong +) + +// File is generated by gobind. Do not edit. + +package OfDouble + +import "Java" + +const _ = Java.Dummy + +const ( +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.PrimitiveIterator.OfDouble proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.PrimitiveIterator.OfDouble. + Cast func(v interface{}) Java.Java_util_PrimitiveIterator_OfDouble +) + +// File is generated by gobind. Do not edit. + +package OfDouble + +import "Java" + +const _ = Java.Dummy + +const ( +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator.OfDouble proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator.OfDouble. + Cast func(v interface{}) Java.Java_util_Spliterator_OfDouble +) + // File is generated by gobind. Do not edit. package Console @@ -334,12 +448,11 @@ type Java_lang_Runnable interface { } type Java_io_InputStream interface { - Read() (int32, error) + Read(a0 ...interface{}) (int32, error) } type Java_util_concurrent_Future interface { - Get() (Java_lang_Object, error) - Get2(a0 int64, a1 Java_util_concurrent_TimeUnit) (Java_lang_Object, error) + Get(a0 ...interface{}) (Java_lang_Object, error) } type Java_lang_Object interface { @@ -355,13 +468,12 @@ type Java_lang_System interface { } type Java_Future interface { - Get() (Java_lang_Object, error) - Get2(a0 int64, a1 Java_util_concurrent_TimeUnit) (Java_lang_Object, error) + Get(a0 ...interface{}) (Java_lang_Object, error) Super() Java_Future } type Java_InputStream interface { - Read() (int32, error) + Read(a0 ...interface{}) (int32, error) Super() Java_InputStream } @@ -374,12 +486,30 @@ type Java_Runnable interface { Super() Java_Runnable } +type Java_util_Iterator interface { +} + +type Java_util_Spliterator interface { +} + type Java_util_PrimitiveIterator_OfInt interface { } type Java_util_Spliterator_OfInt interface { } +type Java_util_PrimitiveIterator_OfLong interface { +} + +type Java_util_Spliterator_OfLong interface { +} + +type Java_util_PrimitiveIterator_OfDouble interface { +} + +type Java_util_Spliterator_OfDouble interface { +} + type Java_io_Console interface { Flush() error } @@ -412,8 +542,14 @@ import "Java/java/Future" import "Java/java/InputStream" import "Java/java/Object" import "Java/java/Runnable" +import "Java/java/util/Iterator" +import "Java/java/util/Spliterator" import "Java/java/util/PrimitiveIterator/OfInt" import "Java/java/util/Spliterator/OfInt" +import "Java/java/util/PrimitiveIterator/OfLong" +import "Java/java/util/Spliterator/OfLong" +import "Java/java/util/PrimitiveIterator/OfDouble" +import "Java/java/util/Spliterator/OfDouble" import "Java/java/io/Console" import "unsafe" @@ -442,8 +578,14 @@ func initClasses() { init_java_InputStream() init_java_Object() init_java_Runnable() + init_java_util_Iterator() + init_java_util_Spliterator() init_java_util_PrimitiveIterator_OfInt() init_java_util_Spliterator_OfInt() + init_java_util_PrimitiveIterator_OfLong() + init_java_util_Spliterator_OfLong() + init_java_util_PrimitiveIterator_OfDouble() + init_java_util_Spliterator_OfDouble() init_java_io_Console() } @@ -511,19 +653,61 @@ type proxy_class_java_io_InputStream _seq.Ref func (p *proxy_class_java_io_InputStream) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_io_InputStream) Read() (int32, error) { - res := C.cproxy_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) +func (p *proxy_class_java_io_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_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 + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.cproxy_java_io_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _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 + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.cproxy_java_io_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _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 } } - return _res, _exc + panic("no overloaded method found for java.io.InputStream.read that matched the arguments") } var class_java_util_concurrent_Future C.jclass @@ -551,55 +735,61 @@ type proxy_class_java_util_concurrent_Future _seq.Ref func (p *proxy_class_java_util_concurrent_Future) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_util_concurrent_Future) Get() (Java.Java_lang_Object, error) { - res := C.cproxy_java_util_concurrent_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) +func (p *proxy_class_java_util_concurrent_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_java_util_concurrent_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 + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.cproxy_java_util_concurrent_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 _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_java_util_concurrent_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_java_util_concurrent_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 + panic("no overloaded method found for java.util.concurrent.Future.get that matched the arguments") } var class_java_lang_Object C.jclass @@ -662,32 +852,125 @@ func init_java_util_Spliterators() { return } class_java_util_Spliterators = clazz - Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2 = func(a0 Java.Java_util_Spliterator_OfInt) Java.Java_util_PrimitiveIterator_OfInt { - var _a0 C.jint = _seq.NullRefNum - if a0 != nil { - _a0 = C.jint(_seq.ToRefNum(a0)) + Spliterators.Iterator = func(a0 Java.Java_util_Spliterator) Java.Java_util_Iterator { + { + var __a0 C.jint = _seq.NullRefNum + if a0 != nil { + __a0 = C.jint(_seq.ToRefNum(a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(__a0) + var _res Java.Java_util_Iterator + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_Iterator) + } else { // foreign object + _res = (*proxy_class_java_util_Iterator)(_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) + } + } + if (_exc != nil) { panic(_exc) } + return _res } - res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(_a0) - var _res Java.Java_util_PrimitiveIterator_OfInt - _res_ref := _seq.FromRefNum(int32(res.res)) - if _res_ref != nil { - if res.res < 0 { // go object - _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfInt) - } else { // foreign object - _res = (*proxy_class_java_util_PrimitiveIterator_OfInt)(_res_ref) + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfInt) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfInt + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfInt) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfInt)(_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) + } + } + if (_exc != nil) { panic(_exc) } + return _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) + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfLong) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfLong + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfLong) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfLong)(_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) + } + } + if (_exc != nil) { panic(_exc) } + return _res } } - if (_exc != nil) { panic(_exc) } - return _res + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfDouble) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfDouble + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfDouble) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfDouble)(_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) + } + } + if (_exc != nil) { panic(_exc) } + return _res + } + } + panic("no overloaded method found for java.util.Spliterators.iterator that matched the arguments") } Spliterators.Cast = func(v interface{}) Java.Java_util_Spliterators { @@ -779,55 +1062,61 @@ type proxy_class_java_Future _seq.Ref func (p *proxy_class_java_Future) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_Future) Get() (Java.Java_lang_Object, error) { - res := C.cproxy_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) +func (p *proxy_class_java_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_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 + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.cproxy_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 _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_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_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 + panic("no overloaded method found for java.Future.get that matched the arguments") } func (p *proxy_class_java_Future) Super() Java.Java_Future { @@ -836,55 +1125,61 @@ func (p *proxy_class_java_Future) Super() Java.Java_Future { type super_java_Future struct {*proxy_class_java_Future} -func (p *super_java_Future) Get() (Java.Java_lang_Object, error) { - res := C.csuper_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) +func (p *super_java_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.csuper_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 + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.csuper_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 _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_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_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 + panic("no overloaded method found for java.Future.get that matched the arguments") } var class_java_InputStream C.jclass @@ -912,19 +1207,61 @@ type proxy_class_java_InputStream _seq.Ref func (p *proxy_class_java_InputStream) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } -func (p *proxy_class_java_InputStream) Read() (int32, error) { - res := C.cproxy_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) +func (p *proxy_class_java_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_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 + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.cproxy_java_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _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 + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.cproxy_java_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _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 } } - return _res, _exc + panic("no overloaded method found for java.InputStream.read that matched the arguments") } func (p *proxy_class_java_InputStream) Super() Java.Java_InputStream { @@ -933,19 +1270,61 @@ func (p *proxy_class_java_InputStream) Super() Java.Java_InputStream { type super_java_InputStream struct {*proxy_class_java_InputStream} -func (p *super_java_InputStream) Read() (int32, error) { - res := C.csuper_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) +func (p *super_java_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.csuper_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 + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.csuper_java_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _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 + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.csuper_java_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _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 } } - return _res, _exc + panic("no overloaded method found for java.InputStream.read that matched the arguments") } var class_java_Object C.jclass @@ -1038,6 +1417,56 @@ func (p *super_java_Runnable) Run() { if (_exc != nil) { panic(_exc) } } +var class_java_util_Iterator C.jclass + +func init_java_util_Iterator() { + cls := C.CString("java/util/Iterator") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_Iterator = clazz + Iterator.Cast = func(v interface{}) Java.Java_util_Iterator { + t := reflect.TypeOf((*proxy_class_java_util_Iterator)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Iterator) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Iterator) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Iterator")) + } + return cv + } +} + +type proxy_class_java_util_Iterator _seq.Ref + +func (p *proxy_class_java_util_Iterator) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +var class_java_util_Spliterator C.jclass + +func init_java_util_Spliterator() { + cls := C.CString("java/util/Spliterator") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_Spliterator = clazz + Spliterator.Cast = func(v interface{}) Java.Java_util_Spliterator { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator _seq.Ref + +func (p *proxy_class_java_util_Spliterator) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + var class_java_util_PrimitiveIterator_OfInt C.jclass func init_java_util_PrimitiveIterator_OfInt() { @@ -1088,6 +1517,106 @@ type proxy_class_java_util_Spliterator_OfInt _seq.Ref func (p *proxy_class_java_util_Spliterator_OfInt) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } +var class_java_util_PrimitiveIterator_OfLong C.jclass + +func init_java_util_PrimitiveIterator_OfLong() { + cls := C.CString("java/util/PrimitiveIterator$OfLong") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_PrimitiveIterator_OfLong = clazz + OfLong.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfLong { + t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfLong)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfLong) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfLong) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfLong")) + } + return cv + } +} + +type proxy_class_java_util_PrimitiveIterator_OfLong _seq.Ref + +func (p *proxy_class_java_util_PrimitiveIterator_OfLong) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +var class_java_util_Spliterator_OfLong C.jclass + +func init_java_util_Spliterator_OfLong() { + cls := C.CString("java/util/Spliterator$OfLong") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_Spliterator_OfLong = clazz + OfLong.Cast = func(v interface{}) Java.Java_util_Spliterator_OfLong { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfLong)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfLong) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfLong) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfLong")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator_OfLong _seq.Ref + +func (p *proxy_class_java_util_Spliterator_OfLong) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +var class_java_util_PrimitiveIterator_OfDouble C.jclass + +func init_java_util_PrimitiveIterator_OfDouble() { + cls := C.CString("java/util/PrimitiveIterator$OfDouble") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_PrimitiveIterator_OfDouble = clazz + OfDouble.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfDouble { + t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfDouble)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfDouble) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfDouble) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfDouble")) + } + return cv + } +} + +type proxy_class_java_util_PrimitiveIterator_OfDouble _seq.Ref + +func (p *proxy_class_java_util_PrimitiveIterator_OfDouble) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +var class_java_util_Spliterator_OfDouble C.jclass + +func init_java_util_Spliterator_OfDouble() { + cls := C.CString("java/util/Spliterator$OfDouble") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if clazz == nil { + return + } + class_java_util_Spliterator_OfDouble = clazz + OfDouble.Cast = func(v interface{}) Java.Java_util_Spliterator_OfDouble { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfDouble)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfDouble) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfDouble) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfDouble")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator_OfDouble _seq.Ref + +func (p *proxy_class_java_util_Spliterator_OfDouble) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + var class_java_io_Console C.jclass func init_java_io_Console() { @@ -1181,19 +1710,23 @@ func proxyjava_Future_Future_Get(refnum C.int32_t) C.int32_t { } //export proxyjava_Future_Get -func proxyjava_Future_Get(refnum C.int32_t) C.int32_t { +func proxyjava_Future_Get(refnum C.int32_t) (C.int32_t, C.int32_t) { ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*java.Future) - res_0 := v.Get() + res_0, res_1 := v.Get() var _res_0 C.int32_t = _seq.NullRefNum if res_0 != nil { _res_0 = C.int32_t(_seq.ToRefNum(res_0)) } - return _res_0 + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 } -//export proxyjava_Future_Get2 -func proxyjava_Future_Get2(refnum C.int32_t, param_p0 C.int64_t, param_p1 C.int32_t) C.int32_t { +//export proxyjava_Future_Get_ +func proxyjava_Future_Get_(refnum C.int32_t, param_p0 C.int64_t, param_p1 C.int32_t) (C.int32_t, C.int32_t) { ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*java.Future) _param_p0 := int64(param_p0) @@ -1206,12 +1739,16 @@ func proxyjava_Future_Get2(refnum C.int32_t, param_p0 C.int64_t, param_p1 C.int3 _param_p1 = (*proxy_class_java_util_concurrent_TimeUnit)(_param_p1_ref) } } - res_0 := v.Get2(_param_p0, _param_p1) + res_0, res_1 := v.Get_(_param_p0, _param_p1) var _res_0 C.int32_t = _seq.NullRefNum if res_0 != nil { _res_0 = C.int32_t(_seq.ToRefNum(res_0)) } - return _res_0 + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 } //export new_java_Future diff --git a/bind/testdata/classes.java.c.golden b/bind/testdata/classes.java.c.golden index a5d7a46..c1469b2 100644 --- a/bind/testdata/classes.java.c.golden +++ b/bind/testdata/classes.java.c.golden @@ -8,13 +8,33 @@ static jclass class_java_lang_Runnable; static jmethodID m_java_lang_Runnable_run; static jclass class_java_io_InputStream; static jmethodID m_java_io_InputStream_read__; +static jmethodID m_java_io_InputStream_read___3B; +static jmethodID m_java_io_InputStream_read___3BII; static jclass class_java_util_concurrent_Future; static jmethodID m_java_util_concurrent_Future_get__; static jmethodID m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2; static jclass class_java_lang_Object; static jclass class_java_util_concurrent_TimeUnit; static jclass class_java_util_Spliterators; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2; static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2; +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2, _a0); + 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_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0) { JNIEnv *env = go_seq_push_local_frame(1); jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); @@ -30,6 +50,36 @@ ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024O return __res; } +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2, _a0); + 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_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2, _a0); + 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; +} + static jclass class_java_lang_System; static jmethodID m_s_java_lang_System_console; ret_jint cproxy_s_java_lang_System_console() { @@ -56,19 +106,29 @@ static jclass class_java_InputStream; static jclass sclass_java_InputStream; static jmethodID m_java_InputStream_read__; static jmethodID sm_java_InputStream_read__; +static jmethodID m_java_InputStream_read___3B; +static jmethodID sm_java_InputStream_read___3B; +static jmethodID m_java_InputStream_read___3BII; +static jmethodID sm_java_InputStream_read___3BII; static jclass class_java_Object; static jclass sclass_java_Object; static jclass class_java_Runnable; static jclass sclass_java_Runnable; static jmethodID m_java_Runnable_run; static jmethodID sm_java_Runnable_run; +static jclass class_java_util_Iterator; +static jclass class_java_util_Spliterator; static jclass class_java_util_PrimitiveIterator_OfInt; static jclass class_java_util_Spliterator_OfInt; +static jclass class_java_util_PrimitiveIterator_OfLong; +static jclass class_java_util_Spliterator_OfLong; +static jclass class_java_util_PrimitiveIterator_OfDouble; +static jclass class_java_util_Spliterator_OfDouble; static jclass class_java_io_Console; static jmethodID m_java_io_Console_flush; void init_proxies() { - JNIEnv *env = go_seq_push_local_frame(14); + JNIEnv *env = go_seq_push_local_frame(20); jclass clazz; clazz = (*env)->FindClass(env, "java/lang/Runnable"); class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz); @@ -76,6 +136,8 @@ void init_proxies() { clazz = (*env)->FindClass(env, "java/io/InputStream"); class_java_io_InputStream = (*env)->NewGlobalRef(env, clazz); m_java_io_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I"); + m_java_io_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I"); + m_java_io_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I"); clazz = (*env)->FindClass(env, "java/util/concurrent/Future"); class_java_util_concurrent_Future = (*env)->NewGlobalRef(env, clazz); m_java_util_concurrent_Future_get__ = go_seq_get_method_id(clazz, "get", "()Ljava/lang/Object;"); @@ -86,7 +148,10 @@ 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); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator;)Ljava/util/Iterator;"); m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfInt;)Ljava/util/PrimitiveIterator$OfInt;"); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfLong;)Ljava/util/PrimitiveIterator$OfLong;"); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfDouble;)Ljava/util/PrimitiveIterator$OfDouble;"); clazz = (*env)->FindClass(env, "java/lang/System"); class_java_lang_System = (*env)->NewGlobalRef(env, clazz); m_s_java_lang_System_console = go_seq_get_static_method_id(clazz, "console", "()Ljava/io/Console;"); @@ -104,6 +169,10 @@ void init_proxies() { sclass_java_InputStream = (*env)->NewGlobalRef(env, sclass_java_InputStream); m_java_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I"); sm_java_InputStream_read__ = go_seq_get_method_id(sclass_java_InputStream, "read", "()I"); + m_java_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I"); + sm_java_InputStream_read___3B = go_seq_get_method_id(sclass_java_InputStream, "read", "([B)I"); + m_java_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I"); + sm_java_InputStream_read___3BII = go_seq_get_method_id(sclass_java_InputStream, "read", "([BII)I"); clazz = (*env)->FindClass(env, "java/Object"); class_java_Object = (*env)->NewGlobalRef(env, clazz); sclass_java_Object = (*env)->GetSuperclass(env, clazz); @@ -114,10 +183,22 @@ void init_proxies() { sclass_java_Runnable = (*env)->NewGlobalRef(env, sclass_java_Runnable); m_java_Runnable_run = go_seq_get_method_id(clazz, "run", "()V"); sm_java_Runnable_run = go_seq_get_method_id(sclass_java_Runnable, "run", "()V"); + clazz = (*env)->FindClass(env, "java/util/Iterator"); + class_java_util_Iterator = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "java/util/Spliterator"); + class_java_util_Spliterator = (*env)->NewGlobalRef(env, clazz); clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfInt"); class_java_util_PrimitiveIterator_OfInt = (*env)->NewGlobalRef(env, clazz); clazz = (*env)->FindClass(env, "java/util/Spliterator$OfInt"); class_java_util_Spliterator_OfInt = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfLong"); + class_java_util_PrimitiveIterator_OfLong = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "java/util/Spliterator$OfLong"); + class_java_util_Spliterator_OfLong = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfDouble"); + class_java_util_PrimitiveIterator_OfDouble = (*env)->NewGlobalRef(env, clazz); + clazz = (*env)->FindClass(env, "java/util/Spliterator$OfDouble"); + class_java_util_Spliterator_OfDouble = (*env)->NewGlobalRef(env, clazz); clazz = (*env)->FindClass(env, "java/io/Console"); class_java_io_Console = (*env)->NewGlobalRef(env, clazz); m_java_io_Console_flush = go_seq_get_method_id(clazz, "flush", "()V"); @@ -151,6 +232,42 @@ ret_jint cproxy_java_io_InputStream_read__(jint this) { return __res; } +ret_jint cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3B, _a0); + 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_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3BII, _a0, _a1, _a2); + 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 @@ -285,6 +402,78 @@ ret_jint csuper_java_InputStream_read__(jint this) { return __res; } +ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3B, _a0); + 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_java_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3B, _a0); + 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_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3BII, _a0, _a1, _a2); + 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_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3BII, _a0, _a1, _a2); + 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_java_Runnable_run(jint this) { JNIEnv *env = go_seq_push_local_frame(1); // Must be a Java object @@ -368,8 +557,10 @@ Java_java_Future__1_1New(JNIEnv *env, jclass clazz) { JNIEXPORT jobject JNICALL Java_java_Future_get__(JNIEnv* env, jobject __this__) { int32_t o = go_seq_to_refnum_go(env, __this__); - int32_t r0 = proxyjava_Future_Get(o); - jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + struct proxyjava_Future_Get_return res = proxyjava_Future_Get(o); + jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); return _r0; } @@ -378,8 +569,10 @@ Java_java_Future_get__JLjava_util_concurrent_TimeUnit_2(JNIEnv* env, jobject __t int32_t o = go_seq_to_refnum_go(env, __this__); int64_t _p0 = (int64_t)p0; int32_t _p1 = go_seq_to_refnum(env, p1); - int32_t r0 = proxyjava_Future_Get2(o, _p0, _p1); - jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + struct proxyjava_Future_Get__return res = proxyjava_Future_Get_(o, _p0, _p1); + jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); return _r0; } diff --git a/bind/testdata/classes.java.golden b/bind/testdata/classes.java.golden index b9d602c..a746c17 100644 --- a/bind/testdata/classes.java.golden +++ b/bind/testdata/classes.java.golden @@ -26,8 +26,8 @@ public final class Future implements Seq.GoObject, java.util.concurrent.Future { public final native java.util.concurrent.Future getFuture(); public final native void setFuture(java.util.concurrent.Future v); - @Override public native java.lang.Object get(); - @Override public native java.lang.Object get(long p0, java.util.concurrent.TimeUnit p1); + @Override public native java.lang.Object get() throws java.lang.InterruptedException, java.util.concurrent.ExecutionException; + @Override public native java.lang.Object get(long p0, java.util.concurrent.TimeUnit p1) throws java.lang.InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException; } // Java class java.InputStream is a proxy for talking to a Go program. diff --git a/bind/testdata/classes.java.h.golden b/bind/testdata/classes.java.h.golden index 16362ed..61aefed 100644 --- a/bind/testdata/classes.java.h.golden +++ b/bind/testdata/classes.java.h.golden @@ -48,6 +48,8 @@ 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 cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint cproxy_java_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); 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_java_Future_get__(jint this); @@ -56,10 +58,17 @@ extern ret_jint cproxy_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint t extern ret_jint csuper_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); extern ret_jint cproxy_java_InputStream_read__(jint this); extern ret_jint csuper_java_InputStream_read__(jint this); +extern ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint csuper_java_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint cproxy_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); +extern ret_jint csuper_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); extern jint cproxy_java_Runnable_run(jint this); extern jint csuper_java_Runnable_run(jint this); extern jint cproxy_java_io_Console_flush(jint this); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0); extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0); extern ret_jint cproxy_s_java_lang_System_console(); // JNI function headers for the Go <=> Java bridge. // gobind -lang=java classes diff --git a/bind/testpkg/javapkg/classes.go b/bind/testpkg/javapkg/classes.go index 5ce80ca..b4fea5a 100644 --- a/bind/testpkg/javapkg/classes.go +++ b/bind/testpkg/javapkg/classes.go @@ -51,7 +51,7 @@ type GoInputStream struct { } func (_ *GoInputStream) Read() (int32, error) { - return 0, IOException.New_Ljava_lang_String_2(IOExceptionMessage) + return 0, IOException.New(IOExceptionMessage) } func NewGoInputStream() *GoInputStream { @@ -66,12 +66,13 @@ func (_ *GoFuture) Cancel(_ bool) bool { return false } -func (_ *GoFuture) Get() lang.Object { - return nil +func (_ *GoFuture) Get() (lang.Object, error) { + return nil, nil } -func (_ *GoFuture) Get2(_ int64, _ concurrent.TimeUnit) lang.Object { - return nil +// Use a trailing underscore to override multiple overloaded methods. +func (_ *GoFuture) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) { + return nil, nil } func (_ *GoFuture) IsCancelled() bool { @@ -153,7 +154,8 @@ func NewJavaObject() lang.Object { } func NewJavaInteger() lang.Integer { - return Integer.New_I(42) + i, _ := Integer.New(int32(42)) + return i } type NoargConstructor struct { diff --git a/bind/testpkg/javapkg/java.go b/bind/testpkg/javapkg/java.go index fa2a3c6..948f13a 100644 --- a/bind/testpkg/javapkg/java.go +++ b/bind/testpkg/javapkg/java.go @@ -30,7 +30,7 @@ func IntegerBytes() int { } func IntegerValueOf(v int32) int32 { - i := Integer.ValueOf_I(v) + i, _ := Integer.ValueOf(v) return i.IntValue() } @@ -45,7 +45,7 @@ func IntegerDecode(v string) (int32, error) { } func IntegerParseInt(v string, radix int32) (int32, error) { - return Integer.ParseInt2(v, radix) + return Integer.ParseInt(v, radix) } func ProvokeRuntimeException() (err error) { diff --git a/example/reverse/reverse/reverse.go b/example/reverse/reverse/reverse.go index 4ec6d99..501be71 100644 --- a/example/reverse/reverse/reverse.go +++ b/example/reverse/reverse/reverse.go @@ -18,9 +18,9 @@ type MainActivity struct { app.AppCompatActivity } -func (a *MainActivity) OnCreate1(this gopkg.MainActivity, b os.Bundle) { - this.Super().OnCreate1(b) - db := DataBindingUtil.SetContentView2(this, rlayout.Activity_main) +func (a *MainActivity) OnCreate(this gopkg.MainActivity, b os.Bundle) { + this.Super().OnCreate(b) + db := DataBindingUtil.SetContentView(this, rlayout.Activity_main) mainBind := ActivityMainBinding.Cast(db) mainBind.SetAct(this) } diff --git a/internal/importers/java/java.go b/internal/importers/java/java.go index 2b9b063..89617c8 100644 --- a/internal/importers/java/java.go +++ b/internal/importers/java/java.go @@ -16,6 +16,7 @@ import ( "errors" "fmt" "os/exec" + "reflect" "strings" "unicode" "unicode/utf8" @@ -35,11 +36,15 @@ type Class struct { JNIName string // "Inner" PkgName string - Funcs []*Func - Methods []*Func + Funcs []*FuncSet + Methods []*FuncSet + // funcMap maps function names. + funcMap map[string]*FuncSet + // FuncMap maps method names. + methodMap map[string]*FuncSet // All methods, including methods from // supers. - AllMethods []*Func + AllMethods []*FuncSet Vars []*Var Supers []string Final bool @@ -50,11 +55,34 @@ type Class struct { HasNoArgCon bool } +// FuncSet is the set of overloaded variants of a function. +// If the function is not overloaded, its FuncSet contains +// one entry. +type FuncSet struct { + Name string + GoName string + Funcs []*Func + CommonSig +} + +// CommonSig is a signature compatible with every +// overloaded variant of a FuncSet. +type CommonSig struct { + // Variadic is set if the signature covers variants + // with varying number of parameters. + Variadic bool + // HasRet is true if at least one variant returns a + // value. + HasRet bool + Throws bool + Params []*Type + Ret *Type +} + // Func is a Java static function or method or constructor. type Func struct { FuncSig ArgDesc string - GoName string // Mangled JNI name JNIName string Static bool @@ -102,6 +130,13 @@ type Importer struct { clsMap map[string]*Class } +// funcRef is a reference to a Java function (static method). +// It is used as a key to filter unused Java functions. +type funcRef struct { + clsName string + goName string +} + const ( Int TypeKind = iota Boolean @@ -167,10 +202,21 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) { } } } + funcRefs := make(map[funcRef]struct{}) + for _, ref := range refs.Refs { + pkgName := strings.Replace(ref.Pkg, "/", ".", -1) + funcRefs[funcRef{pkgName, ref.Name}] = struct{}{} + } classes, err := j.importClasses(names, true) if err != nil { return nil, err } + j.filterReferences(classes, refs, funcRefs) + supers, err := j.importReferencedClasses(classes) + if err != nil { + return nil, err + } + j.filterReferences(supers, refs, funcRefs) // 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. @@ -182,6 +228,7 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) { if _, exists := j.clsMap[n]; exists { continue } + clsSet[n] = struct{}{} cls := &Class{ Name: n, FindName: n, @@ -199,52 +246,193 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) { classes = append(classes, cls) j.clsMap[cls.Name] = cls } - j.initClasses(classes, refs) // Include implicit classes that are used in parameter or return values. - newClasses := classes - for len(newClasses) > 0 { - var impNames []string - var impClasses []*Class - for _, cls := range newClasses { - for _, funcs := range [][]*Func{cls.Funcs, cls.AllMethods} { - for _, f := range funcs { + for _, cls := range classes { + for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { + for _, fs := range fsets { + for _, f := range fs.Funcs { names := j.implicitFuncTypes(f) for _, name := range names { if _, exists := clsSet[name]; exists { continue } clsSet[name] = struct{}{} - if cls, exists := j.clsMap[name]; exists { - impClasses = append(impClasses, cls) - } else { - impNames = append(impNames, name) - } + classes = append(classes, j.clsMap[name]) } } } } - imports, err := j.importClasses(impNames, false) - if err != nil { - return nil, err + } + for _, cls := range j.clsMap { + j.fillFuncSigs(cls.Funcs) + j.fillFuncSigs(cls.Methods) + for _, m := range cls.Methods { + j.fillSuperSigs(cls, m) } - impClasses = append(impClasses, imports...) - j.initClasses(impClasses, refs) - classes = append(classes, impClasses...) - newClasses = impClasses + } + for _, cls := range j.clsMap { + j.fillAllMethods(cls) + } + // Include classes that appear as ancestor types for overloaded signatures. + for _, cls := range classes { + for _, funcs := range [][]*FuncSet{cls.Funcs, cls.AllMethods} { + for _, f := range funcs { + for _, p := range f.Params { + if p == nil || p.Kind != Object { + continue + } + if _, exists := clsSet[p.Class]; !exists { + clsSet[p.Class] = struct{}{} + classes = append(classes, j.clsMap[p.Class]) + } + } + if t := f.Ret; t != nil && t.Kind == Object { + if _, exists := clsSet[t.Class]; !exists { + clsSet[t.Class] = struct{}{} + classes = append(classes, j.clsMap[t.Class]) + } + } + } + } + } + for _, cls := range classes { + j.fillJNINames(cls.Funcs) + j.fillJNINames(cls.AllMethods) } j.fillThrowables(classes) return classes, nil } -func (j *Importer) initClasses(classes []*Class, refs *importers.References) { - for _, cls := range classes { - j.fillAllMethods(cls) +func (j *Importer) fillJNINames(funcs []*FuncSet) { + for _, fs := range funcs { + for _, f := range fs.Funcs { + f.JNIName = JNIMangle(f.Name) + if len(fs.Funcs) > 1 { + f.JNIName += "__" + JNIMangle(f.ArgDesc) + } + } } - for _, cls := range classes { - j.mangleOverloads(cls.AllMethods) - j.mangleOverloads(cls.Funcs) +} + +// commonType finds the most specific type common to t1 and t2. +// If t1 and t2 are both Java classes, the most specific ancestor +// class is returned. +// Else if the types are equal, their type is returned. +// Finally, nil is returned, indicating no common type. +func commonType(clsMap map[string]*Class, t1, t2 *Type) *Type { + if t1 == nil || t2 == nil { + return nil + } + if reflect.DeepEqual(t1, t2) { + return t1 + } + if t1.Kind != Object || t2.Kind != Object { + // The types are fundamentally incompatible + return nil + } + superSet := make(map[string]struct{}) + supers := []string{t1.Class} + for len(supers) > 0 { + var newSupers []string + for _, s := range supers { + cls := clsMap[s] + superSet[s] = struct{}{} + newSupers = append(newSupers, cls.Supers...) + } + supers = newSupers + } + supers = []string{t2.Class} + for len(supers) > 0 { + var newSupers []string + for _, s := range supers { + if _, exists := superSet[s]; exists { + return &Type{Kind: Object, Class: s} + } + cls := clsMap[s] + newSupers = append(newSupers, cls.Supers...) + } + supers = newSupers + } + return &Type{Kind: Object, Class: "java.lang.Object"} +} + +// combineSigs finds the most specific function signature +// that covers all its overload variants. +// If a function has only one variant, its common signature +// is the signature of that variant. +func combineSigs(clsMap map[string]*Class, sigs ...CommonSig) CommonSig { + var common CommonSig + minp := len(sigs[0].Params) + for i := 1; i < len(sigs); i++ { + sig := sigs[i] + n := len(sig.Params) + common.Variadic = common.Variadic || sig.Variadic || n != minp + if n < minp { + minp = n + } + } + for i, sig := range sigs { + for j, p := range sig.Params { + idx := j + // If the common signature is variadic, combine all parameters in the + // last parameter type of the shortest parameter list. + if idx > minp { + idx = minp + } + if idx < len(common.Params) { + common.Params[idx] = commonType(clsMap, common.Params[idx], p) + } else { + common.Params = append(common.Params, p) + } + } + common.Throws = common.Throws || sig.Throws + common.HasRet = common.HasRet || sig.HasRet + if i > 0 { + common.Ret = commonType(clsMap, common.Ret, sig.Ret) + } else { + common.Ret = sig.Ret + } + } + return common +} + +// fillSuperSigs combines methods signatures with super class signatures, +// to preserve the assignability of classes to their super classes. +// +// For example, the class +// +// class A { +// void f(); +// } +// +// is by itself represented by the Go interface +// +// type A interface { +// f() +// } +// +// However, if class +// +// class B extends A { +// void f(int); +// } +// +// is also imported, it will be represented as +// +// type B interface { +// f(...int32) +// } +// +// To make Go B assignable to Go A, the signature of A's f must +// be updated to f(...int32) as well. +func (j *Importer) fillSuperSigs(cls *Class, m *FuncSet) { + for _, s := range cls.Supers { + sup := j.clsMap[s] + if sm, exists := sup.methodMap[m.GoName]; exists { + sm.CommonSig = combineSigs(j.clsMap, sm.CommonSig, m.CommonSig) + } + j.fillSuperSigs(sup, m) } - j.filterReferences(classes, refs) } func (v *Var) Constant() bool { @@ -377,20 +565,11 @@ func (t *Type) JNICallType() string { } } -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) - cls := j.clsMap[pkgName] - if cls == nil { - continue - } - refFuncs[[...]string{pkgName, ref.Name}] = struct{}{} - } +func (j *Importer) filterReferences(classes []*Class, refs *importers.References, funcRefs map[funcRef]struct{}) { for _, cls := range classes { - var filtered []*Func + var filtered []*FuncSet for _, f := range cls.Funcs { - if _, exists := refFuncs[[...]string{cls.Name, f.GoName}]; exists { + if _, exists := funcRefs[funcRef{cls.Name, f.GoName}]; exists { filtered = append(filtered, f) } } @@ -402,16 +581,10 @@ func (j *Importer) filterReferences(classes []*Class, refs *importers.References } } cls.Methods = filtered - filtered = nil - for _, m := range cls.AllMethods { - if _, exists := refs.Names[m.GoName]; exists { - filtered = append(filtered, m) - } - } - cls.AllMethods = filtered } } +// importClasses imports the named classes from the classpaths of the Importer. func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) { if len(names) == 0 { return nil, nil @@ -442,31 +615,54 @@ func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*C for _, name := range names { cls, err := j.scanClass(s, name) if err != nil { - if allowMissingClasses && err == errClsNotFound { + if err == errClsNotFound && allowMissingClasses { continue } - return nil, err + if err == errClsNotFound && name != "android.databinding.DataBindingComponent" { + return nil, err + } + // The Android Databinding library generates android.databinding.DataBindingComponent + // too late in the build process for the gobind plugin to import it. Synthesize a class + // for it instead. + cls = &Class{ + Name: name, + FindName: name, + Interface: true, + PkgName: "databinding", + JNIName: JNIMangle(name), + } } classes = append(classes, cls) j.clsMap[name] = cls } + return classes, nil +} + +// importReferencedClasses imports all implicit classes (super types, parameter and +// return types) for the given classes not already imported. +func (j *Importer) importReferencedClasses(classes []*Class) ([]*Class, error) { + var allCls []*Class // Include methods from extended or implemented classes. - unkCls := classes for { - var unknown []string - for _, cls := range unkCls { - unknown = j.unknownSuperClasses(cls, unknown) + set := make(map[string]struct{}) + for _, cls := range classes { + j.unknownImplicitClasses(cls, set) } - if len(unknown) == 0 { + if len(set) == 0 { break } - newCls, err := j.importClasses(unknown, false) + var names []string + for n := range set { + names = append(names, n) + } + newCls, err := j.importClasses(names, false) if err != nil { return nil, err } - unkCls = newCls + allCls = append(allCls, newCls...) + classes = newCls } - return classes, nil + return allCls, nil } func (j *Importer) implicitFuncTypes(f *Func) []string { @@ -482,21 +678,43 @@ func (j *Importer) implicitFuncTypes(f *Func) []string { return unk } -func (j *Importer) unknownSuperClasses(cls *Class, unk []string) []string { -loop: - for _, n := range cls.Supers { - if s, exists := j.clsMap[n]; exists { - unk = j.unknownSuperClasses(s, unk) - } else { - for _, u := range unk { - if u == n { - continue loop +func (j *Importer) unknownImplicitClasses(cls *Class, set map[string]struct{}) { + for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { + for _, fs := range fsets { + for _, f := range fs.Funcs { + names := j.implicitFuncTypes(f) + for _, name := range names { + if _, exists := j.clsMap[name]; !exists { + set[name] = struct{}{} + } } } - unk = append(unk, n) } } - return unk + for _, n := range cls.Supers { + if s, exists := j.clsMap[n]; exists { + j.unknownImplicitClasses(s, set) + } else { + set[n] = struct{}{} + } + } +} + +func (j *Importer) implicitFuncClasses(funcs []*FuncSet, impl []string) []string { + var l []string + for _, fs := range funcs { + for _, f := range fs.Funcs { + if rt := f.Ret; rt != nil && rt.Kind == Object { + l = append(l, rt.Class) + } + for _, t := range f.Params { + if t.Kind == Object { + l = append(l, t.Class) + } + } + } + } + return impl } func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { @@ -522,13 +740,6 @@ func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { if err != nil { return nil, err } - if len(cls.Supers) == 0 { - if name == "java.lang.Object" { - cls.HasNoArgCon = true - } else if !cls.Interface { - cls.Supers = append(cls.Supers, "java.lang.Object") - } - } cls.JNIName = JNIMangle(cls.Name) clsElems := strings.Split(cls.Name, ".") cls.PkgName = clsElems[len(clsElems)-1] @@ -606,18 +817,37 @@ func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { } } for _, f := range funcs { + var m map[string]*FuncSet + var l *[]*FuncSet + goName := initialUpper(f.Name) if f.Static || f.Constructor { - cls.Funcs = append(cls.Funcs, f) + m = cls.funcMap + l = &cls.Funcs } else { - cls.Methods = append(cls.Methods, f) + m = cls.methodMap + l = &cls.Methods } + fs, exists := m[goName] + if !exists { + fs = &FuncSet{ + Name: f.Name, + GoName: goName, + } + m[goName] = fs + *l = append(*l, fs) + } + fs.Funcs = append(fs.Funcs, f) } return cls, nil } func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { + isRoot := name == "java.lang.Object" cls := &Class{ - Name: name, + Name: name, + funcMap: make(map[string]*FuncSet), + methodMap: make(map[string]*FuncSet), + HasNoArgCon: isRoot, } const ( stMod = iota @@ -625,6 +855,7 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { stExt stImpl ) + superClsDecl := isRoot st := stMod var w []byte // if > 0, we're inside a generics declaration @@ -641,6 +872,9 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { case '<': gennest++ case '{': + if !superClsDecl && !cls.Interface { + cls.Supers = append(cls.Supers, "java.lang.Object") + } return cls, nil case ' ', ',': if gennest > 0 { @@ -655,6 +889,7 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { } cls.FindName = w case stExt: + superClsDecl = true cls.Supers = append(cls.Supers, w) case stImpl: if !cls.Interface { @@ -800,68 +1035,61 @@ func (j *Importer) fillThrowableFor(cls, thrCls *Class) { } } +func commonSig(f *Func) CommonSig { + return CommonSig{ + Params: f.Params, + Ret: f.Ret, + HasRet: f.Ret != nil, + Throws: f.Throws != "", + } +} + +func (j *Importer) fillFuncSigs(funcs []*FuncSet) { + for _, fs := range funcs { + var sigs []CommonSig + for _, f := range fs.Funcs { + sigs = append(sigs, commonSig(f)) + } + fs.CommonSig = combineSigs(j.clsMap, sigs...) + } +} + func (j *Importer) fillAllMethods(cls *Class) { if len(cls.AllMethods) > 0 { return } - if len(cls.Supers) == 0 { - cls.AllMethods = cls.Methods - return - } for _, supName := range cls.Supers { super := j.clsMap[supName] j.fillAllMethods(super) } - methods := make(map[FuncSig]struct{}) + var fsets []*FuncSet + fsets = append(fsets, cls.Methods...) for _, supName := range cls.Supers { super := j.clsMap[supName] - for _, f := range super.AllMethods { - if _, exists := methods[f.FuncSig]; !exists { - methods[f.FuncSig] = struct{}{} - cls.AllMethods = append(cls.AllMethods, f) + fsets = append(fsets, super.AllMethods...) + } + sigs := make(map[FuncSig]struct{}) + methods := make(map[string]*FuncSet) + for _, fs := range fsets { + clsFs, exists := methods[fs.Name] + if !exists { + clsFs = &FuncSet{ + Name: fs.Name, + GoName: fs.GoName, + CommonSig: fs.CommonSig, } + cls.AllMethods = append(cls.AllMethods, clsFs) + methods[fs.Name] = clsFs + } else { + // Combine the (overloaded) signature with the other variants. + clsFs.CommonSig = combineSigs(j.clsMap, clsFs.CommonSig, fs.CommonSig) } - } - for _, f := range cls.Methods { - if _, exists := methods[f.FuncSig]; !exists { - cls.AllMethods = append(cls.AllMethods, f) - } - } -} - -// 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) { - overloads := make(map[string][]*Func) - for i, f := range allFuncs { - // Name mangling is per class so copy the function first. - f := *f - allFuncs[i] = &f - overloads[f.Name] = append(overloads[f.Name], &f) - } - for _, funcs := range overloads { - for _, f := range funcs { - f.GoName = initialUpper(f.Name) - f.JNIName = JNIMangle(f.Name) - } - if len(funcs) == 1 { - continue - } - lengths := make(map[int]int) - for _, f := range funcs { - f.JNIName += "__" + JNIMangle(f.ArgDesc) - lengths[len(f.Params)]++ - } - for _, f := range funcs { - n := len(f.Params) - if lengths[n] > 1 { - f.GoName += "_" + JNIMangle(f.ArgDesc) + for _, f := range fs.Funcs { + if _, exists := sigs[f.FuncSig]; exists { continue } - if n > 0 { - f.GoName = fmt.Sprintf("%s%d", f.GoName, n) - } + sigs[f.FuncSig] = struct{}{} + clsFs.Funcs = append(clsFs.Funcs, f) } } } diff --git a/internal/importers/java/java_test.go b/internal/importers/java/java_test.go index c970a5a..7d25d21 100644 --- a/internal/importers/java/java_test.go +++ b/internal/importers/java/java_test.go @@ -18,20 +18,32 @@ func TestImport(t *testing.T) { tests := []struct { ref importers.PkgRef name string - methods []*Func + methods []*FuncSet }{ { ref: importers.PkgRef{"java/lang/Object", "equals"}, name: "java.lang.Object", - methods: []*Func{ - &Func{FuncSig: FuncSig{Name: "equals", Desc: "(Ljava/lang/Object;)Z"}, ArgDesc: "Ljava/lang/Object;", GoName: "Equals", JNIName: "equals", Public: true, Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}}, + methods: []*FuncSet{ + &FuncSet{ + Name: "equals", + GoName: "Equals", + CommonSig: CommonSig{ + Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}, HasRet: true, + }, + Funcs: []*Func{&Func{FuncSig: FuncSig{Name: "equals", Desc: "(Ljava/lang/Object;)Z"}, ArgDesc: "Ljava/lang/Object;", JNIName: "equals", Public: true, Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}}}, + }, }, }, { ref: importers.PkgRef{"java/lang/Runnable", "run"}, name: "java.lang.Runnable", - methods: []*Func{ - &Func{FuncSig: FuncSig{Name: "run", Desc: "()V"}, ArgDesc: "", GoName: "Run", JNIName: "run", Public: true, Abstract: true}, + methods: []*FuncSet{ + &FuncSet{ + Name: "run", + GoName: "Run", + CommonSig: CommonSig{}, + Funcs: []*Func{&Func{FuncSig: FuncSig{Name: "run", Desc: "()V"}, ArgDesc: "", JNIName: "run", Public: true, Abstract: true}}, + }, }, }, } @@ -56,7 +68,7 @@ func TestImport(t *testing.T) { } loop: for _, exp := range test.methods { - for _, got := range cls.Methods { + for _, got := range cls.AllMethods { if reflect.DeepEqual(exp, got) { continue loop } @@ -65,3 +77,118 @@ func TestImport(t *testing.T) { } } } + +func testClsMap() map[string]*Class { + // + // A-- + // / \ \ + // B C \ + // \ / \ \ + // D E F + // + return map[string]*Class{ + "A": &Class{}, + "B": &Class{ + Supers: []string{"A"}, + }, + "C": &Class{ + Supers: []string{"A"}, + }, + "D": &Class{ + Supers: []string{"B", "C"}, + }, + "E": &Class{ + Supers: []string{"C"}, + }, + "F": &Class{ + Supers: []string{"A"}, + }, + } +} + +func TestCommonTypes(t *testing.T) { + clsMap := testClsMap() + tests := [][3]*Type{ + {nil, nil, nil}, + {&Type{Kind: Int}, nil, nil}, + {&Type{Kind: Int}, &Type{Kind: Float}, nil}, + {&Type{Kind: Int}, &Type{Kind: Int}, &Type{Kind: Int}}, + {&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "D"}}, + {&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "E"}, &Type{Kind: Object, Class: "C"}}, + {&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "F"}, &Type{Kind: Object, Class: "A"}}, + {&Type{Kind: Object, Class: "B"}, &Type{Kind: Object, Class: "E"}, &Type{Kind: Object, Class: "A"}}, + } + for _, test := range tests { + t1, t2, exp := test[0], test[1], test[2] + got := commonType(clsMap, t1, t2) + if !reflect.DeepEqual(got, exp) { + t.Errorf("commonType(%+v, %+v) = %+v, expected %+v", t1, t2, got, exp) + } + } +} + +func TestCommonSig(t *testing.T) { + tests := []struct { + Sigs []CommonSig + CommonSig + }{ + { + Sigs: []CommonSig{ + CommonSig{}, // f() + }, + CommonSig: CommonSig{}, // f() + }, + { + Sigs: []CommonSig{ + CommonSig{Throws: true, HasRet: true, Ret: &Type{Kind: Int}}, // int f() throws + }, + // int f() throws + CommonSig: CommonSig{Throws: true, HasRet: true, Ret: &Type{Kind: Int}}, + }, + { + Sigs: []CommonSig{ + CommonSig{}, // f() + CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int) + }, + CommonSig: CommonSig{ // f(int...) + Variadic: true, + Params: []*Type{&Type{Kind: Int}}, + }, + }, + { + Sigs: []CommonSig{ + CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int) + CommonSig{Params: []*Type{&Type{Kind: Float}}}, // f(float) + }, + CommonSig: CommonSig{ // f(interface{}) + Params: []*Type{nil}, + }, + }, + { + Sigs: []CommonSig{ + CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int) + CommonSig{Params: []*Type{&Type{Kind: Int}, &Type{Kind: Int}}}, // f(int, int) + }, + CommonSig: CommonSig{ // f(int, int...) + Variadic: true, + Params: []*Type{&Type{Kind: Int}, &Type{Kind: Int}}, + }, + }, + { + Sigs: []CommonSig{ + CommonSig{Params: []*Type{&Type{Kind: Object, Class: "A"}}}, // f(A) + CommonSig{Params: []*Type{&Type{Kind: Object, Class: "B"}}}, // f(B) + }, + CommonSig: CommonSig{ // f(A) + Params: []*Type{&Type{Kind: Object, Class: "A"}}, + }, + }, + } + clsMap := testClsMap() + for _, test := range tests { + got := combineSigs(clsMap, test.Sigs...) + if !reflect.DeepEqual(got, test.CommonSig) { + t.Errorf("commonSig(%+v) = %+v, expected %+v", test.Sigs, got, test.CommonSig) + } + } +}