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 )