github.com/F4RD1N/gomobile@v1.0.1/bind/genclasses.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bind
     6  
     7  import (
     8  	"fmt"
     9  	"path"
    10  	"reflect"
    11  	"strings"
    12  	"unicode"
    13  	"unicode/utf8"
    14  
    15  	"github.com/F4RD1N/gomobile/internal/importers"
    16  	"github.com/F4RD1N/gomobile/internal/importers/java"
    17  )
    18  
    19  type (
    20  	// ClassGen generates Go and C stubs for Java classes so import statements
    21  	// on the form
    22  	//
    23  	//
    24  	// import "Java/classpath/to/Class"
    25  	//
    26  	// will work.
    27  	ClassGen struct {
    28  		*Printer
    29  		// JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go
    30  		// package name to create the full Java package name.
    31  		JavaPkg  string
    32  		imported map[string]struct{}
    33  		// The list of imported Java classes
    34  		classes []*java.Class
    35  		// The list of Go package paths with Java interfaces inside
    36  		jpkgs []string
    37  		// For each Go package path, the list of Java classes.
    38  		typePkgs map[string][]*java.Class
    39  		// For each Go package path, the Java class with static functions
    40  		// or constants.
    41  		clsPkgs map[string]*java.Class
    42  		// goClsMap is the map of Java class names to Go type names, qualified with package name. Go types
    43  		// that implement Java classes need Super methods and Unwrap methods.
    44  		goClsMap map[string]string
    45  		// goClsImports is the list of imports of user packages that contains the Go types implementing Java
    46  		// classes.
    47  		goClsImports []string
    48  	}
    49  )
    50  
    51  func (g *ClassGen) isSupported(t *java.Type) bool {
    52  	switch t.Kind {
    53  	case java.Array:
    54  		// TODO: Support all array types
    55  		return t.Elem.Kind == java.Byte
    56  	default:
    57  		return true
    58  	}
    59  }
    60  
    61  func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool {
    62  	for _, f := range fs.Funcs {
    63  		if g.isFuncSupported(f) {
    64  			return true
    65  		}
    66  	}
    67  	return false
    68  }
    69  
    70  func (g *ClassGen) isFuncSupported(f *java.Func) bool {
    71  	for _, a := range f.Params {
    72  		if !g.isSupported(a) {
    73  			return false
    74  		}
    75  	}
    76  	if f.Ret != nil {
    77  		return g.isSupported(f.Ret)
    78  	}
    79  	return true
    80  }
    81  
    82  func (g *ClassGen) goType(t *java.Type, local bool) string {
    83  	if t == nil {
    84  		// interface{} is used for parameters types for overloaded methods
    85  		// where no common ancestor type exists.
    86  		return "interface{}"
    87  	}
    88  	switch t.Kind {
    89  	case java.Int:
    90  		return "int32"
    91  	case java.Boolean:
    92  		return "bool"
    93  	case java.Short:
    94  		return "int16"
    95  	case java.Char:
    96  		return "uint16"
    97  	case java.Byte:
    98  		return "byte"
    99  	case java.Long:
   100  		return "int64"
   101  	case java.Float:
   102  		return "float32"
   103  	case java.Double:
   104  		return "float64"
   105  	case java.String:
   106  		return "string"
   107  	case java.Array:
   108  		return "[]" + g.goType(t.Elem, local)
   109  	case java.Object:
   110  		name := goClsName(t.Class)
   111  		if !local {
   112  			name = "Java." + name
   113  		}
   114  		return name
   115  	default:
   116  		panic("invalid kind")
   117  	}
   118  }
   119  
   120  // Init initializes the class wrapper generator. Classes is the
   121  // list of classes to wrap, goClasses is the list of Java classes
   122  // implemented in Go.
   123  func (g *ClassGen) Init(classes []*java.Class, goClasses []importers.Struct) {
   124  	g.goClsMap = make(map[string]string)
   125  	impMap := make(map[string]struct{})
   126  	for _, s := range goClasses {
   127  		n := s.Pkg + "." + s.Name
   128  		jn := n
   129  		if g.JavaPkg != "" {
   130  			jn = g.JavaPkg + "." + jn
   131  		}
   132  		g.goClsMap[jn] = n
   133  		if _, exists := impMap[s.PkgPath]; !exists {
   134  			impMap[s.PkgPath] = struct{}{}
   135  			g.goClsImports = append(g.goClsImports, s.PkgPath)
   136  		}
   137  	}
   138  	g.classes = classes
   139  	g.imported = make(map[string]struct{})
   140  	g.typePkgs = make(map[string][]*java.Class)
   141  	g.clsPkgs = make(map[string]*java.Class)
   142  	pkgSet := make(map[string]struct{})
   143  	for _, cls := range classes {
   144  		g.imported[cls.Name] = struct{}{}
   145  		clsPkg := strings.Replace(cls.Name, ".", "/", -1)
   146  		g.clsPkgs[clsPkg] = cls
   147  		typePkg := path.Dir(clsPkg)
   148  		g.typePkgs[typePkg] = append(g.typePkgs[typePkg], cls)
   149  		if _, exists := pkgSet[clsPkg]; !exists {
   150  			pkgSet[clsPkg] = struct{}{}
   151  			g.jpkgs = append(g.jpkgs, clsPkg)
   152  		}
   153  		if _, exists := pkgSet[typePkg]; !exists {
   154  			pkgSet[typePkg] = struct{}{}
   155  			g.jpkgs = append(g.jpkgs, typePkg)
   156  		}
   157  	}
   158  }
   159  
   160  // Packages return the list of Go packages to be generated.
   161  func (g *ClassGen) Packages() []string {
   162  	return g.jpkgs
   163  }
   164  
   165  func (g *ClassGen) GenPackage(idx int) {
   166  	jpkg := g.jpkgs[idx]
   167  	g.Printf(gobindPreamble)
   168  	g.Printf("package %s\n\n", path.Base(jpkg))
   169  	g.Printf("import \"Java\"\n\n")
   170  	g.Printf("const _ = Java.Dummy\n\n")
   171  	for _, cls := range g.typePkgs[jpkg] {
   172  		g.Printf("type %s Java.%s\n", cls.PkgName, goClsName(cls.Name))
   173  	}
   174  	if cls, ok := g.clsPkgs[jpkg]; ok {
   175  		g.Printf("const (\n")
   176  		g.Indent()
   177  		// Constants
   178  		for _, v := range cls.Vars {
   179  			if g.isSupported(v.Type) && v.Constant() {
   180  				g.Printf("%s = %s\n", initialUpper(v.Name), v.Val)
   181  			}
   182  		}
   183  		g.Outdent()
   184  		g.Printf(")\n\n")
   185  
   186  		g.Printf("var (\n")
   187  		g.Indent()
   188  		// Functions
   189  	loop:
   190  		for _, fs := range cls.Funcs {
   191  			for _, f := range fs.Funcs {
   192  				if f.Public && g.isFuncSupported(f) {
   193  					g.Printf("%s func", fs.GoName)
   194  					g.genFuncDecl(false, fs)
   195  					g.Printf("\n")
   196  					continue loop
   197  				}
   198  			}
   199  		}
   200  		g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name)
   201  		g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n")
   202  		g.Printf("// not extend or implement %s.\n", cls.Name)
   203  		g.Printf("Cast func(v interface{}) Java.%s\n", goClsName(cls.Name))
   204  		g.Outdent()
   205  		g.Printf(")\n\n")
   206  	}
   207  }
   208  
   209  func (g *ClassGen) GenGo() {
   210  	g.Printf(classesGoHeader)
   211  	for _, cls := range g.classes {
   212  		pkgName := strings.Replace(cls.Name, ".", "/", -1)
   213  		g.Printf("import %q\n", "Java/"+pkgName)
   214  	}
   215  	for _, imp := range g.goClsImports {
   216  		g.Printf("import %q\n", imp)
   217  	}
   218  	if len(g.classes) > 0 {
   219  		g.Printf("import \"unsafe\"\n\n")
   220  		g.Printf("import \"reflect\"\n\n")
   221  		g.Printf("import \"fmt\"\n\n")
   222  	}
   223  	g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n")
   224  	g.Printf("// Suppress unused package error\n\n")
   225  	g.Printf("var _ = _seq.FromRefNum\n")
   226  	g.Printf("const _ = Java.Dummy\n\n")
   227  	g.Printf("//export initClasses\n")
   228  	g.Printf("func initClasses() {\n")
   229  	g.Indent()
   230  	g.Printf("C.init_proxies()\n")
   231  	for _, cls := range g.classes {
   232  		g.Printf("init_%s()\n", cls.JNIName)
   233  	}
   234  	g.Outdent()
   235  	g.Printf("}\n\n")
   236  	for _, cls := range g.classes {
   237  		g.genGo(cls)
   238  	}
   239  }
   240  
   241  func (g *ClassGen) GenH() {
   242  	g.Printf(classesHHeader)
   243  	for _, tn := range []string{"jint", "jboolean", "jshort", "jchar", "jbyte", "jlong", "jfloat", "jdouble", "nstring", "nbyteslice"} {
   244  		g.Printf("typedef struct ret_%s {\n", tn)
   245  		g.Printf("	%s res;\n", tn)
   246  		g.Printf("	jint exc;\n")
   247  		g.Printf("} ret_%s;\n", tn)
   248  	}
   249  	g.Printf("\n")
   250  	for _, cls := range g.classes {
   251  		for _, fs := range cls.AllMethods {
   252  			for _, f := range fs.Funcs {
   253  				if !g.isFuncSupported(f) {
   254  					continue
   255  				}
   256  				g.Printf("extern ")
   257  				g.genCMethodDecl("cproxy", cls.JNIName, f)
   258  				g.Printf(";\n")
   259  				if _, ok := g.goClsMap[cls.Name]; ok {
   260  					g.Printf("extern ")
   261  					g.genCMethodDecl("csuper", cls.JNIName, f)
   262  					g.Printf(";\n")
   263  				}
   264  			}
   265  		}
   266  	}
   267  	for _, cls := range g.classes {
   268  		g.genH(cls)
   269  	}
   270  }
   271  
   272  func (g *ClassGen) GenC() {
   273  	g.Printf(classesCHeader)
   274  	for _, cls := range g.classes {
   275  		g.Printf("static jclass class_%s;\n", cls.JNIName)
   276  		if _, ok := g.goClsMap[cls.Name]; ok {
   277  			g.Printf("static jclass sclass_%s;\n", cls.JNIName)
   278  		}
   279  		for _, fs := range cls.Funcs {
   280  			for _, f := range fs.Funcs {
   281  				if !f.Public || !g.isFuncSupported(f) {
   282  					continue
   283  				}
   284  				g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName)
   285  			}
   286  		}
   287  		for _, fs := range cls.AllMethods {
   288  			for _, f := range fs.Funcs {
   289  				if g.isFuncSupported(f) {
   290  					g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName)
   291  					if _, ok := g.goClsMap[cls.Name]; ok {
   292  						g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName)
   293  					}
   294  				}
   295  			}
   296  		}
   297  		g.genC(cls)
   298  	}
   299  	g.Printf("\n")
   300  	g.Printf("void init_proxies() {\n")
   301  	g.Indent()
   302  	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(g.classes))
   303  	g.Printf("jclass clazz;\n")
   304  	for _, cls := range g.classes {
   305  		g.Printf("clazz = go_seq_find_class(%q);\n", strings.Replace(cls.FindName, ".", "/", -1))
   306  		g.Printf("if (clazz != NULL) {\n")
   307  		g.Indent()
   308  		g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName)
   309  		if _, ok := g.goClsMap[cls.Name]; ok {
   310  			g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName)
   311  			g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName)
   312  		}
   313  		for _, fs := range cls.Funcs {
   314  			for _, f := range fs.Funcs {
   315  				if !f.Public || !g.isFuncSupported(f) {
   316  					continue
   317  				}
   318  				g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName)
   319  				if f.Constructor {
   320  					g.Printf("go_seq_get_method_id(clazz, \"<init>\", %q);\n", f.Desc)
   321  				} else {
   322  					g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc)
   323  				}
   324  			}
   325  		}
   326  		for _, fs := range cls.AllMethods {
   327  			for _, f := range fs.Funcs {
   328  				if g.isFuncSupported(f) {
   329  					g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc)
   330  					if _, ok := g.goClsMap[cls.Name]; ok {
   331  						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)
   332  					}
   333  				}
   334  			}
   335  		}
   336  		g.Outdent()
   337  		g.Printf("}\n")
   338  	}
   339  	g.Printf("go_seq_pop_local_frame(env);\n")
   340  	g.Outdent()
   341  	g.Printf("}\n\n")
   342  	for _, cls := range g.classes {
   343  		for _, fs := range cls.AllMethods {
   344  			for _, f := range fs.Funcs {
   345  				if !g.isFuncSupported(f) {
   346  					continue
   347  				}
   348  				g.genCMethodDecl("cproxy", cls.JNIName, f)
   349  				g.genCMethodBody(cls, f, false)
   350  				if _, ok := g.goClsMap[cls.Name]; ok {
   351  					g.genCMethodDecl("csuper", cls.JNIName, f)
   352  					g.genCMethodBody(cls, f, true)
   353  				}
   354  			}
   355  		}
   356  	}
   357  }
   358  
   359  func (g *ClassGen) GenInterfaces() {
   360  	g.Printf(classesPkgHeader)
   361  	for _, cls := range g.classes {
   362  		g.genInterface(cls)
   363  	}
   364  }
   365  
   366  func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) {
   367  	g.Printf(" {\n")
   368  	g.Indent()
   369  	// Add 1 for the 'this' argument
   370  	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)+1)
   371  	g.Printf("// Must be a Java object\n")
   372  	g.Printf("jobject _this = go_seq_from_refnum(env, this, NULL, NULL);\n")
   373  	for i, a := range f.Params {
   374  		g.genCToJava(fmt.Sprintf("a%d", i), a)
   375  	}
   376  	if f.Ret != nil {
   377  		g.Printf("%s res = ", f.Ret.JNIType())
   378  	}
   379  	g.Printf("(*env)->Call")
   380  	if virtual {
   381  		g.Printf("Nonvirtual")
   382  	}
   383  	if f.Ret != nil {
   384  		g.Printf(f.Ret.JNICallType())
   385  	} else {
   386  		g.Printf("Void")
   387  	}
   388  	g.Printf("Method(env, _this, ")
   389  	if virtual {
   390  		g.Printf("sclass_%s, sm_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
   391  	} else {
   392  		g.Printf("m_%s_%s", cls.JNIName, f.JNIName)
   393  	}
   394  	for i := range f.Params {
   395  		g.Printf(", _a%d", i)
   396  	}
   397  	g.Printf(");\n")
   398  	g.Printf("jobject _exc = go_seq_get_exception(env);\n")
   399  	g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
   400  	if f.Ret != nil {
   401  		g.genCRetClear("res", f.Ret, "_exc")
   402  		g.genJavaToC("res", f.Ret)
   403  	}
   404  	g.Printf("go_seq_pop_local_frame(env);\n")
   405  	if f.Ret != nil {
   406  		g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
   407  		g.Printf("return __res;\n")
   408  	} else {
   409  		g.Printf("return _exc_ref;\n")
   410  	}
   411  	g.Outdent()
   412  	g.Printf("}\n\n")
   413  }
   414  
   415  func initialUpper(s string) string {
   416  	if s == "" {
   417  		return ""
   418  	}
   419  	r, n := utf8.DecodeRuneInString(s)
   420  	return string(unicode.ToUpper(r)) + s[n:]
   421  }
   422  
   423  func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) {
   424  	g.Printf("(")
   425  	for i, a := range fs.Params {
   426  		if i > 0 {
   427  			g.Printf(", ")
   428  		}
   429  		g.Printf("a%d ", i)
   430  		if i == len(fs.Params)-1 && fs.Variadic {
   431  			g.Printf("...")
   432  		}
   433  		g.Printf(g.goType(a, local))
   434  	}
   435  	g.Printf(")")
   436  	if fs.Throws {
   437  		if fs.HasRet {
   438  			g.Printf(" (%s, error)", g.goType(fs.Ret, local))
   439  		} else {
   440  			g.Printf(" error")
   441  		}
   442  	} else if fs.HasRet {
   443  		g.Printf(" %s", g.goType(fs.Ret, local))
   444  	}
   445  }
   446  
   447  func (g *ClassGen) genC(cls *java.Class) {
   448  	for _, fs := range cls.Funcs {
   449  		for _, f := range fs.Funcs {
   450  			if !f.Public || !g.isFuncSupported(f) {
   451  				continue
   452  			}
   453  			g.genCFuncDecl(cls.JNIName, f)
   454  			g.Printf(" {\n")
   455  			g.Indent()
   456  			g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params))
   457  			for i, a := range f.Params {
   458  				g.genCToJava(fmt.Sprintf("a%d", i), a)
   459  			}
   460  			if f.Constructor {
   461  				g.Printf("jobject res = (*env)->NewObject(env")
   462  			} else if f.Ret != nil {
   463  				g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType())
   464  			} else {
   465  				g.Printf("(*env)->CallStaticVoidMethod(env")
   466  			}
   467  			g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
   468  			for i := range f.Params {
   469  				g.Printf(", _a%d", i)
   470  			}
   471  			g.Printf(");\n")
   472  			g.Printf("jobject _exc = go_seq_get_exception(env);\n")
   473  			g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
   474  			if f.Ret != nil {
   475  				g.genCRetClear("res", f.Ret, "_exc")
   476  				g.genJavaToC("res", f.Ret)
   477  			}
   478  			g.Printf("go_seq_pop_local_frame(env);\n")
   479  			if f.Ret != nil {
   480  				g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
   481  				g.Printf("return __res;\n")
   482  			} else {
   483  				g.Printf("return _exc_ref;\n")
   484  			}
   485  			g.Outdent()
   486  			g.Printf("}\n\n")
   487  		}
   488  	}
   489  }
   490  
   491  func (g *ClassGen) genH(cls *java.Class) {
   492  	for _, fs := range cls.Funcs {
   493  		for _, f := range fs.Funcs {
   494  			if !f.Public || !g.isFuncSupported(f) {
   495  				continue
   496  			}
   497  			g.Printf("extern ")
   498  			g.genCFuncDecl(cls.JNIName, f)
   499  			g.Printf(";\n")
   500  		}
   501  	}
   502  }
   503  
   504  func (g *ClassGen) genCMethodDecl(prefix, jniName string, f *java.Func) {
   505  	if f.Ret != nil {
   506  		g.Printf("ret_%s", f.Ret.CType())
   507  	} else {
   508  		// Return only the exception, if any
   509  		g.Printf("jint")
   510  	}
   511  	g.Printf(" %s_%s_%s(jint this", prefix, jniName, f.JNIName)
   512  	for i, a := range f.Params {
   513  		g.Printf(", %s a%d", a.CType(), i)
   514  	}
   515  	g.Printf(")")
   516  }
   517  
   518  func (g *ClassGen) genCFuncDecl(jniName string, f *java.Func) {
   519  	if f.Ret != nil {
   520  		g.Printf("ret_%s", f.Ret.CType())
   521  	} else {
   522  		// Return only the exception, if any
   523  		g.Printf("jint")
   524  	}
   525  	g.Printf(" cproxy_s_%s_%s(", jniName, f.JNIName)
   526  	for i, a := range f.Params {
   527  		if i > 0 {
   528  			g.Printf(", ")
   529  		}
   530  		g.Printf("%s a%d", a.CType(), i)
   531  	}
   532  	g.Printf(")")
   533  }
   534  
   535  func (g *ClassGen) genGo(cls *java.Class) {
   536  	g.Printf("var class_%s C.jclass\n\n", cls.JNIName)
   537  	g.Printf("func init_%s() {\n", cls.JNIName)
   538  	g.Indent()
   539  	g.Printf("cls := C.CString(%q)\n", strings.Replace(cls.FindName, ".", "/", -1))
   540  	g.Printf("clazz := C.go_seq_find_class(cls)\n")
   541  	g.Printf("C.free(unsafe.Pointer(cls))\n")
   542  	// Before Go 1.11 clazz was a pointer value, an uintptr after.
   543  	g.Printf("if uintptr(clazz) == 0 {\n")
   544  	g.Printf("	return\n")
   545  	g.Printf("}\n")
   546  	g.Printf("class_%s = clazz\n", cls.JNIName)
   547  	for _, fs := range cls.Funcs {
   548  		var supported bool
   549  		for _, f := range fs.Funcs {
   550  			if f.Public && g.isFuncSupported(f) {
   551  				supported = true
   552  				break
   553  			}
   554  		}
   555  		if !supported {
   556  			continue
   557  		}
   558  		g.Printf("%s.%s = func", cls.PkgName, fs.GoName)
   559  		g.genFuncDecl(false, fs)
   560  		g.genFuncBody(cls, fs, "cproxy_s", true)
   561  	}
   562  	g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name))
   563  	g.Indent()
   564  	g.Printf("t := reflect.TypeOf((*proxy_class_%s)(nil))\n", cls.JNIName)
   565  	g.Printf("cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_%s)\n", cls.JNIName)
   566  	g.Printf("ref := C.jint(_seq.ToRefNum(cv))\n")
   567  	g.Printf("if C.go_seq_isinstanceof(ref, class_%s) != 1 {\n", cls.JNIName)
   568  	g.Printf("	panic(fmt.Errorf(\"%%T is not an instance of %%s\", v, %q))\n", cls.Name)
   569  	g.Printf("}\n")
   570  	g.Printf("return cv\n")
   571  	g.Outdent()
   572  	g.Printf("}\n")
   573  	g.Outdent()
   574  	g.Printf("}\n\n")
   575  	g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName)
   576  	g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 {\n", cls.JNIName)
   577  	g.Indent()
   578  	g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n")
   579  	g.Outdent()
   580  	g.Printf("}\n\n")
   581  	for _, fs := range cls.AllMethods {
   582  		if !g.isFuncSetSupported(fs) {
   583  			continue
   584  		}
   585  		g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName)
   586  		g.genFuncDecl(false, fs)
   587  		g.genFuncBody(cls, fs, "cproxy", false)
   588  	}
   589  	if cls.Throwable {
   590  		g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName)
   591  		g.Printf("	return p.ToString()\n")
   592  		g.Printf("}\n")
   593  	}
   594  	if goName, ok := g.goClsMap[cls.Name]; ok {
   595  		g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name))
   596  		g.Printf("	return &super_%s{p}\n", cls.JNIName)
   597  		g.Printf("}\n\n")
   598  		g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName)
   599  		g.Printf("func (p *proxy_class_%s) Unwrap() interface{} {\n", cls.JNIName)
   600  		g.Indent()
   601  		g.Printf("goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__()))\n")
   602  		g.Printf("return _seq.FromRefNum(int32(goRefnum)).Get().(*%s)\n", goName)
   603  		g.Outdent()
   604  		g.Printf("}\n\n")
   605  		for _, fs := range cls.AllMethods {
   606  			if !g.isFuncSetSupported(fs) {
   607  				continue
   608  			}
   609  			g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName)
   610  			g.genFuncDecl(false, fs)
   611  			g.genFuncBody(cls, fs, "csuper", false)
   612  		}
   613  	}
   614  }
   615  
   616  // genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically,
   617  // by inspecting the number of arguments (if the FuncSet contains varying parameter counts),
   618  // and their types.
   619  func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) {
   620  	maxp := len(fs.Funcs[0].Params)
   621  	minp := maxp
   622  	// sort the function variants into argument sizes.
   623  	buckets := make(map[int][]*java.Func)
   624  	numF := 0
   625  	for _, f := range fs.Funcs {
   626  		if !g.isFuncSupported(f) {
   627  			continue
   628  		}
   629  		numF++
   630  		n := len(f.Params)
   631  		if n < minp {
   632  			minp = n
   633  		} else if n > maxp {
   634  			maxp = n
   635  		}
   636  		buckets[n] = append(buckets[n], f)
   637  	}
   638  	g.Printf(" {\n")
   639  	g.Indent()
   640  	if len(buckets) != 1 {
   641  		// Switch over the number of arguments.
   642  		g.Printf("switch %d + len(a%d) {\n", minp, minp)
   643  	}
   644  	for i := minp; i <= maxp; i++ {
   645  		funcs := buckets[i]
   646  		if len(funcs) == 0 {
   647  			continue
   648  		}
   649  		if len(buckets) != 1 {
   650  			g.Printf("case %d:\n", i)
   651  			g.Indent()
   652  		}
   653  		for _, f := range funcs {
   654  			if len(funcs) > 1 {
   655  				g.Printf("{\n")
   656  				g.Indent()
   657  			}
   658  			var argNames []string
   659  			var preds []string
   660  			for i, a := range f.Params {
   661  				var ct *java.Type
   662  				var argName string
   663  				if i >= minp {
   664  					argName = fmt.Sprintf("a%d[%d]", minp, i-minp)
   665  					ct = fs.Params[minp]
   666  				} else {
   667  					argName = fmt.Sprintf("a%d", i)
   668  					ct = fs.Params[i]
   669  				}
   670  				if !reflect.DeepEqual(ct, a) {
   671  					g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false))
   672  					argName = fmt.Sprintf("_a%d", i)
   673  					preds = append(preds, fmt.Sprintf("ok%d", i))
   674  				}
   675  				argNames = append(argNames, argName)
   676  			}
   677  			if len(preds) > 0 {
   678  				g.Printf("if %s {\n", strings.Join(preds, " && "))
   679  				g.Indent()
   680  			}
   681  			for i, a := range f.Params {
   682  				g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient)
   683  			}
   684  			g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName)
   685  			if !static {
   686  				g.Printf("C.jint(p.Bind_proxy_refnum__())")
   687  			}
   688  			for i := range f.Params {
   689  				if !static || i > 0 {
   690  					g.Printf(", ")
   691  				}
   692  				g.Printf("__a%d", i)
   693  			}
   694  			g.Printf(")\n")
   695  			g.genFuncRet(fs, f, numF > 1)
   696  			if len(preds) > 0 {
   697  				g.Outdent()
   698  				g.Printf("}\n")
   699  			}
   700  			if len(funcs) > 1 {
   701  				g.Outdent()
   702  				g.Printf("}\n")
   703  			}
   704  		}
   705  		if len(buckets) != 1 {
   706  			g.Outdent()
   707  		}
   708  	}
   709  	if len(buckets) != 1 {
   710  		g.Printf("}\n")
   711  	}
   712  	if numF > 1 {
   713  		g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name)
   714  	}
   715  	g.Outdent()
   716  	g.Printf("}\n\n")
   717  }
   718  
   719  func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func, mustReturn bool) {
   720  	if f.Ret != nil {
   721  		g.genRead("_res", "res.res", f.Ret, modeRetained)
   722  		g.genRefRead("_exc", "res.exc", "error", "proxy_error", true)
   723  	} else {
   724  		g.genRefRead("_exc", "res", "error", "proxy_error", true)
   725  	}
   726  	if !fs.Throws {
   727  		g.Printf("if (_exc != nil) { panic(_exc) }\n")
   728  		if fs.HasRet {
   729  			if f.Ret != nil {
   730  				g.Printf("return _res\n")
   731  			} else {
   732  				// The variant doesn't return a value, but the common
   733  				// signature does. Use nil as a placeholder return value.
   734  				g.Printf("return nil\n")
   735  			}
   736  		} else if mustReturn {
   737  			// If there are overloaded variants, return here to avoid the fallback
   738  			// panic generated in genFuncBody.
   739  			g.Printf("return\n")
   740  		}
   741  	} else {
   742  		if fs.HasRet {
   743  			if f.Ret != nil {
   744  				g.Printf("return _res, _exc\n")
   745  			} else {
   746  				// As above, use a nil placeholder return value.
   747  				g.Printf("return nil, _exc\n")
   748  			}
   749  		} else {
   750  			g.Printf("return _exc\n")
   751  		}
   752  	}
   753  }
   754  
   755  func (g *ClassGen) genRead(to, from string, t *java.Type, mode varMode) {
   756  	switch t.Kind {
   757  	case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
   758  		g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from)
   759  	case java.Boolean:
   760  		g.Printf("%s := %s != C.JNI_FALSE\n", to, from)
   761  	case java.String:
   762  		g.Printf("%s := decodeString(%s)\n", to, from)
   763  	case java.Array:
   764  		if t.Elem.Kind != java.Byte {
   765  			panic("unsupported array type")
   766  		}
   767  		g.Printf("%s := toSlice(%s, %v)\n", to, from, mode == modeRetained)
   768  	case java.Object:
   769  		_, hasProxy := g.imported[t.Class]
   770  		g.genRefRead(to, from, g.goType(t, false), "proxy_class_"+flattenName(t.Class), hasProxy)
   771  	default:
   772  		panic("invalid kind")
   773  	}
   774  }
   775  
   776  func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasProxy bool) {
   777  	g.Printf("var %s %s\n", to, intfName)
   778  	g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from)
   779  	g.Printf("if %s_ref != nil {\n", to)
   780  	g.Printf("	if %s < 0 { // go object\n", from)
   781  	g.Printf("		%s = %s_ref.Get().(%s)\n", to, to, intfName)
   782  	g.Printf("	} else { // foreign object\n")
   783  	if hasProxy {
   784  		g.Printf("		%s = (*%s)(%s_ref)\n", to, proxyName, to)
   785  	} else {
   786  		g.Printf("		%s = %s_ref\n", to, to)
   787  	}
   788  	g.Printf("	}\n")
   789  	g.Printf("}\n")
   790  }
   791  
   792  func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) {
   793  	switch t.Kind {
   794  	case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
   795  		g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v)
   796  	case java.Boolean:
   797  		g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst)
   798  		g.Printf("if %s {\n", v)
   799  		g.Printf("	%s = C.jboolean(C.JNI_TRUE)\n", dst)
   800  		g.Printf("}\n")
   801  	case java.String:
   802  		g.Printf("%s := encodeString(%s)\n", dst, v)
   803  	case java.Array:
   804  		if t.Elem.Kind != java.Byte {
   805  			panic("unsupported array type")
   806  		}
   807  		g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained)
   808  	case java.Object:
   809  		g.Printf("var %s C.jint = _seq.NullRefNum\n", dst)
   810  		g.Printf("if %s != nil {\n", v)
   811  		g.Printf("	%s = C.jint(_seq.ToRefNum(%s))\n", dst, v)
   812  		g.Printf("}\n")
   813  	default:
   814  		panic("invalid kind")
   815  	}
   816  }
   817  
   818  // genCRetClear clears the result value from a JNI call if an exception was
   819  // raised.
   820  func (g *ClassGen) genCRetClear(v string, t *java.Type, exc string) {
   821  	g.Printf("if (%s != NULL) {\n", exc)
   822  	g.Indent()
   823  	switch t.Kind {
   824  	case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
   825  		g.Printf("%s = 0;\n", v)
   826  	default:
   827  		// Assume a nullable type. It will break if we missed a type.
   828  		g.Printf("%s = NULL;\n", v)
   829  	}
   830  	g.Outdent()
   831  	g.Printf("}\n")
   832  }
   833  
   834  func (g *ClassGen) genJavaToC(v string, t *java.Type) {
   835  	switch t.Kind {
   836  	case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
   837  		g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
   838  	case java.String:
   839  		g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", v, v)
   840  	case java.Array:
   841  		if t.Elem.Kind != java.Byte {
   842  			panic("unsupported array type")
   843  		}
   844  		g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, 1);\n", v, v)
   845  	case java.Object:
   846  		g.Printf("jint _%s = go_seq_to_refnum(env, %s);\n", v, v)
   847  	default:
   848  		panic("invalid kind")
   849  	}
   850  }
   851  
   852  func (g *ClassGen) genCToJava(v string, t *java.Type) {
   853  	switch t.Kind {
   854  	case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
   855  		g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
   856  	case java.String:
   857  		g.Printf("jstring _%s = go_seq_to_java_string(env, %s);\n", v, v)
   858  	case java.Array:
   859  		if t.Elem.Kind != java.Byte {
   860  			panic("unsupported array type")
   861  		}
   862  		g.Printf("jbyteArray _%s = go_seq_to_java_bytearray(env, %s, 0);\n", v, v)
   863  	case java.Object:
   864  		g.Printf("jobject _%s = go_seq_from_refnum(env, %s, NULL, NULL);\n", v, v)
   865  	default:
   866  		panic("invalid kind")
   867  	}
   868  }
   869  
   870  func goClsName(n string) string {
   871  	return initialUpper(strings.Replace(n, ".", "_", -1))
   872  }
   873  
   874  func (g *ClassGen) genInterface(cls *java.Class) {
   875  	g.Printf("type %s interface {\n", goClsName(cls.Name))
   876  	g.Indent()
   877  	// Methods
   878  	for _, fs := range cls.AllMethods {
   879  		if !g.isFuncSetSupported(fs) {
   880  			continue
   881  		}
   882  		g.Printf(fs.GoName)
   883  		g.genFuncDecl(true, fs)
   884  		g.Printf("\n")
   885  	}
   886  	if goName, ok := g.goClsMap[cls.Name]; ok {
   887  		g.Printf("Super() %s\n", goClsName(cls.Name))
   888  		g.Printf("// Unwrap returns the Go object this Java instance\n")
   889  		g.Printf("// is wrapping.\n")
   890  		g.Printf("// The return value is a %s, but the delclared type is\n", goName)
   891  		g.Printf("// interface{} to avoid import cycles.\n")
   892  		g.Printf("Unwrap() interface{}\n")
   893  	}
   894  	if cls.Throwable {
   895  		g.Printf("Error() string\n")
   896  	}
   897  	g.Outdent()
   898  	g.Printf("}\n\n")
   899  }
   900  
   901  // Flatten java class names. "java.package.Class$Inner" is converted to
   902  // "java_package_Class_Inner"
   903  func flattenName(n string) string {
   904  	return strings.Replace(strings.Replace(n, ".", "_", -1), "$", "_", -1)
   905  }
   906  
   907  var (
   908  	classesPkgHeader = gobindPreamble + `
   909  package Java
   910  
   911  // Used to silence this package not used errors
   912  const Dummy = 0
   913  
   914  `
   915  	classesCHeader = gobindPreamble + `
   916  #include <jni.h>
   917  #include "seq.h"
   918  #include "classes.h"
   919  
   920  `
   921  	classesHHeader = gobindPreamble + `
   922  #include <jni.h>
   923  #include "seq.h"
   924  
   925  extern void init_proxies();
   926  
   927  `
   928  
   929  	javaImplHeader = gobindPreamble
   930  
   931  	classesGoHeader = gobindPreamble + `
   932  package main
   933  
   934  /*
   935  #include <stdlib.h> // for free()
   936  #include <jni.h>
   937  #include "seq.h"
   938  #include "classes.h"
   939  */
   940  import "C"
   941  
   942  import (
   943  	"Java"
   944  	_seq "github.com/F4RD1N/gomobile/bind/seq"
   945  )
   946  
   947  `
   948  )