internal,bind: resolve overloaded methods at runtime

Before this CL, calling overloaded methods on reverse bound Java
classes and interfaces involved confusing and ugly name mangling.
If a set of methods with the same name differed only in argument count,
the mangling was simply adding the argument count to the name:

func F()
func F1(int32)

But if two or more methods had the same number of arguments, the type
had to be appended:

func (...) F() int32
func (...) F1(int32) (int32, error)
func (...) F__I(int32, int32)
func (...) F__JLjava_util_concurrent_TimeUnit_2(int64, concurrent.TimeUnit)

This CL sacrifices a bit of type safety and performance to regain the
convenience and simplicity of Go by resolving overloaded method dispatch
at runtime.

Overloaded Java methods are combined to one Go method that, when invoked,
determines the correct Java method variant at runtime.

The signature of the Go method  is compatible with every Java method with
that name. For the example above, the single Go method becomes the most
general

func (...) F(...interface{}) (interface{}, error)

The method is variadic to cover function with a varying number of
arguments, and it returns interface{} to cover int32, int64 and no
argument. Finally, it returns an error to cover the variant that returns
an error. The generator tries to be specific; for example

func G1(int32) int32
func G2(int32, int32) int32

becomes

func G(int32, ...int32) int32

Overriding Java methods in Go is changed to use the Go parameter types to
determine to correct Java method. To avoid name clashes when overriding
multiple overloaded methods, trailing underscores in the method name are
ignored when matching Java methods.  See the Get methods of GoFuture in
bind/testpkg/javapkg for an example.

Change-Id: I6ac3e024141daa8fc2c35187865c5d7a63368094
Reviewed-on: https://go-review.googlesource.com/35186
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur 2017-01-16 14:08:12 +01:00
parent 1aa9ad5c48
commit 3884e8cb98
12 changed files with 1888 additions and 543 deletions

View File

@ -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, \"<init>\", %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, \"<init>\", %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 {

View File

@ -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)
}

View File

@ -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() {

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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.

View File

@ -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

View File

@ -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 {

View File

@ -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) {

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}