github.com/TimaSlipko/gomobile@v1.0.8/internal/importers/java/java.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 // The java package takes the result of an AST traversal by the 6 // importers package and queries the java command for the type 7 // information for the referenced Java classes and interfaces. 8 // 9 // It is the of go/types for Java types and is used by the bind 10 // package to generate Go wrappers for Java API on Android. 11 package java 12 13 import ( 14 "bufio" 15 "bytes" 16 "errors" 17 "fmt" 18 "os/exec" 19 "reflect" 20 "strings" 21 "unicode" 22 "unicode/utf8" 23 24 "github.com/TimaSlipko/gomobile/internal/importers" 25 ) 26 27 // Class is the bind representation of a Java class or 28 // interface. 29 // Use Import to convert class references to Class. 30 type Class struct { 31 // "java.pkg.Class.Inner" 32 Name string 33 // "java.pkg.Class$Inner" 34 FindName string 35 // JNI mangled name 36 JNIName string 37 // "Inner" 38 PkgName string 39 Funcs []*FuncSet 40 Methods []*FuncSet 41 // funcMap maps function names. 42 funcMap map[string]*FuncSet 43 // FuncMap maps method names. 44 methodMap map[string]*FuncSet 45 // All methods, including methods from 46 // supers. 47 AllMethods []*FuncSet 48 Vars []*Var 49 Supers []string 50 Final bool 51 Abstract bool 52 Interface bool 53 Throwable bool 54 // Whether the class has a no-arg constructor 55 HasNoArgCon bool 56 } 57 58 // FuncSet is the set of overloaded variants of a function. 59 // If the function is not overloaded, its FuncSet contains 60 // one entry. 61 type FuncSet struct { 62 Name string 63 GoName string 64 Funcs []*Func 65 CommonSig 66 } 67 68 // CommonSig is a signature compatible with every 69 // overloaded variant of a FuncSet. 70 type CommonSig struct { 71 // Variadic is set if the signature covers variants 72 // with varying number of parameters. 73 Variadic bool 74 // HasRet is true if at least one variant returns a 75 // value. 76 HasRet bool 77 Throws bool 78 Params []*Type 79 Ret *Type 80 } 81 82 // Func is a Java static function or method or constructor. 83 type Func struct { 84 FuncSig 85 ArgDesc string 86 // Mangled JNI name 87 JNIName string 88 Static bool 89 Abstract bool 90 Final bool 91 Public bool 92 Constructor bool 93 Params []*Type 94 Ret *Type 95 Decl string 96 Throws string 97 } 98 99 // FuncSig uniquely identifies a Java Func. 100 type FuncSig struct { 101 Name string 102 // The method descriptor, in JNI format. 103 Desc string 104 } 105 106 // Var is a Java member variable. 107 type Var struct { 108 Name string 109 Static bool 110 Final bool 111 Val string 112 Type *Type 113 } 114 115 // Type is a Java type. 116 type Type struct { 117 Kind TypeKind 118 Class string 119 Elem *Type 120 } 121 122 type TypeKind int 123 124 type Importer struct { 125 // Bootclasspath string 126 Classpath string 127 // JavaPkg is java package name for generated classes. 128 JavaPkg string 129 130 clsMap map[string]*Class 131 } 132 133 // funcRef is a reference to a Java function (static method). 134 // It is used as a key to filter unused Java functions. 135 type funcRef struct { 136 clsName string 137 goName string 138 } 139 140 type errClsNotFound struct { 141 name string 142 } 143 144 const ( 145 Int TypeKind = iota 146 Boolean 147 Short 148 Char 149 Byte 150 Long 151 Float 152 Double 153 String 154 Array 155 Object 156 ) 157 158 func (e *errClsNotFound) Error() string { 159 return "class not found: " + e.name 160 } 161 162 // IsAvailable reports whether the required tools are available for 163 // Import to work. In particular, IsAvailable checks the existence 164 // of the javap binary. 165 func IsAvailable() bool { 166 _, err := javapPath() 167 return err == nil 168 } 169 170 func javapPath() (string, error) { 171 return exec.LookPath("javap") 172 } 173 174 // Import returns Java Class descriptors for a list of references. 175 // 176 // The javap command from the Java SDK is used to dump 177 // class information. Its output looks like this: 178 // 179 // Compiled from "System.java" 180 // public final class java.lang.System { 181 // 182 // public static final java.io.InputStream in; 183 // descriptor: Ljava/io/InputStream; 184 // public static final java.io.PrintStream out; 185 // descriptor: Ljava/io/PrintStream; 186 // public static final java.io.PrintStream err; 187 // descriptor: Ljava/io/PrintStream; 188 // public static void setIn(java.io.InputStream); 189 // descriptor: (Ljava/io/InputStream;)V 190 // 191 // ... 192 // 193 // } 194 func (j *Importer) Import(refs *importers.References) ([]*Class, error) { 195 if j.clsMap == nil { 196 j.clsMap = make(map[string]*Class) 197 } 198 clsSet := make(map[string]struct{}) 199 var names []string 200 for _, ref := range refs.Refs { 201 // The reference could be to some/pkg.Class or some/pkg/Class.Identifier. Include both. 202 pkg := strings.Replace(ref.Pkg, "/", ".", -1) 203 for _, cls := range []string{pkg, pkg + "." + ref.Name} { 204 if _, exists := clsSet[cls]; !exists { 205 clsSet[cls] = struct{}{} 206 names = append(names, cls) 207 } 208 } 209 } 210 // Make sure toString() is included; it is called when wrapping Java exception types to Go 211 // errors. 212 refs.Names["ToString"] = struct{}{} 213 funcRefs := make(map[funcRef]struct{}) 214 for _, ref := range refs.Refs { 215 pkgName := strings.Replace(ref.Pkg, "/", ".", -1) 216 funcRefs[funcRef{pkgName, ref.Name}] = struct{}{} 217 } 218 classes, err := j.importClasses(names, true) 219 if err != nil { 220 return nil, err 221 } 222 j.filterReferences(classes, refs, funcRefs) 223 supers, err := j.importReferencedClasses(classes) 224 if err != nil { 225 return nil, err 226 } 227 j.filterReferences(supers, refs, funcRefs) 228 // Embedders refer to every exported Go struct that will have its class 229 // generated. Allow Go code to reverse bind to those classes by synthesizing 230 // their class descriptors. 231 for _, emb := range refs.Embedders { 232 n := emb.Pkg + "." + emb.Name 233 if j.JavaPkg != "" { 234 n = j.JavaPkg + "." + n 235 } 236 if _, exists := j.clsMap[n]; exists { 237 continue 238 } 239 clsSet[n] = struct{}{} 240 cls := &Class{ 241 Name: n, 242 FindName: n, 243 JNIName: JNIMangle(n), 244 PkgName: emb.Name, 245 HasNoArgCon: true, 246 } 247 for _, ref := range emb.Refs { 248 jpkg := strings.Replace(ref.Pkg, "/", ".", -1) 249 super := jpkg + "." + ref.Name 250 if _, exists := j.clsMap[super]; !exists { 251 return nil, fmt.Errorf("failed to find Java class %s, embedded by %s", super, n) 252 } 253 cls.Supers = append(cls.Supers, super) 254 } 255 classes = append(classes, cls) 256 j.clsMap[cls.Name] = cls 257 } 258 // Include implicit classes that are used in parameter or return values. 259 for _, cls := range classes { 260 for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { 261 for _, fs := range fsets { 262 for _, f := range fs.Funcs { 263 names := j.implicitFuncTypes(f) 264 for _, name := range names { 265 if _, exists := clsSet[name]; exists { 266 continue 267 } 268 clsSet[name] = struct{}{} 269 classes = append(classes, j.clsMap[name]) 270 } 271 } 272 } 273 } 274 } 275 for _, cls := range j.clsMap { 276 j.fillFuncSigs(cls.Funcs) 277 j.fillFuncSigs(cls.Methods) 278 for _, m := range cls.Methods { 279 j.fillSuperSigs(cls, m) 280 } 281 } 282 for _, cls := range j.clsMap { 283 j.fillAllMethods(cls) 284 } 285 // Include classes that appear as ancestor types for overloaded signatures. 286 for _, cls := range classes { 287 for _, funcs := range [][]*FuncSet{cls.Funcs, cls.AllMethods} { 288 for _, f := range funcs { 289 for _, p := range f.Params { 290 if p == nil || p.Kind != Object { 291 continue 292 } 293 if _, exists := clsSet[p.Class]; !exists { 294 clsSet[p.Class] = struct{}{} 295 classes = append(classes, j.clsMap[p.Class]) 296 } 297 } 298 if t := f.Ret; t != nil && t.Kind == Object { 299 if _, exists := clsSet[t.Class]; !exists { 300 clsSet[t.Class] = struct{}{} 301 classes = append(classes, j.clsMap[t.Class]) 302 } 303 } 304 } 305 } 306 } 307 for _, cls := range classes { 308 j.fillJNINames(cls.Funcs) 309 j.fillJNINames(cls.AllMethods) 310 } 311 j.fillThrowables(classes) 312 return classes, nil 313 } 314 315 func (j *Importer) fillJNINames(funcs []*FuncSet) { 316 for _, fs := range funcs { 317 for _, f := range fs.Funcs { 318 f.JNIName = JNIMangle(f.Name) 319 if len(fs.Funcs) > 1 { 320 f.JNIName += "__" + JNIMangle(f.ArgDesc) 321 } 322 } 323 } 324 } 325 326 // commonType finds the most specific type common to t1 and t2. 327 // If t1 and t2 are both Java classes, the most specific ancestor 328 // class is returned. 329 // Else if the types are equal, their type is returned. 330 // Finally, nil is returned, indicating no common type. 331 func commonType(clsMap map[string]*Class, t1, t2 *Type) *Type { 332 if t1 == nil || t2 == nil { 333 return nil 334 } 335 if reflect.DeepEqual(t1, t2) { 336 return t1 337 } 338 if t1.Kind != Object || t2.Kind != Object { 339 // The types are fundamentally incompatible 340 return nil 341 } 342 superSet := make(map[string]struct{}) 343 supers := []string{t1.Class} 344 for len(supers) > 0 { 345 var newSupers []string 346 for _, s := range supers { 347 cls := clsMap[s] 348 superSet[s] = struct{}{} 349 newSupers = append(newSupers, cls.Supers...) 350 } 351 supers = newSupers 352 } 353 supers = []string{t2.Class} 354 for len(supers) > 0 { 355 var newSupers []string 356 for _, s := range supers { 357 if _, exists := superSet[s]; exists { 358 return &Type{Kind: Object, Class: s} 359 } 360 cls := clsMap[s] 361 newSupers = append(newSupers, cls.Supers...) 362 } 363 supers = newSupers 364 } 365 return &Type{Kind: Object, Class: "java.lang.Object"} 366 } 367 368 // combineSigs finds the most specific function signature 369 // that covers all its overload variants. 370 // If a function has only one variant, its common signature 371 // is the signature of that variant. 372 func combineSigs(clsMap map[string]*Class, sigs ...CommonSig) CommonSig { 373 var common CommonSig 374 minp := len(sigs[0].Params) 375 for i := 1; i < len(sigs); i++ { 376 sig := sigs[i] 377 n := len(sig.Params) 378 common.Variadic = common.Variadic || sig.Variadic || n != minp 379 if n < minp { 380 minp = n 381 } 382 } 383 for i, sig := range sigs { 384 for j, p := range sig.Params { 385 idx := j 386 // If the common signature is variadic, combine all parameters in the 387 // last parameter type of the shortest parameter list. 388 if idx > minp { 389 idx = minp 390 } 391 if idx < len(common.Params) { 392 common.Params[idx] = commonType(clsMap, common.Params[idx], p) 393 } else { 394 common.Params = append(common.Params, p) 395 } 396 } 397 common.Throws = common.Throws || sig.Throws 398 common.HasRet = common.HasRet || sig.HasRet 399 if i > 0 { 400 common.Ret = commonType(clsMap, common.Ret, sig.Ret) 401 } else { 402 common.Ret = sig.Ret 403 } 404 } 405 return common 406 } 407 408 // fillSuperSigs combines methods signatures with super class signatures, 409 // to preserve the assignability of classes to their super classes. 410 // 411 // For example, the class 412 // 413 // class A { 414 // void f(); 415 // } 416 // 417 // is by itself represented by the Go interface 418 // 419 // type A interface { 420 // f() 421 // } 422 // 423 // However, if class 424 // 425 // class B extends A { 426 // void f(int); 427 // } 428 // 429 // is also imported, it will be represented as 430 // 431 // type B interface { 432 // f(...int32) 433 // } 434 // 435 // To make Go B assignable to Go A, the signature of A's f must 436 // be updated to f(...int32) as well. 437 func (j *Importer) fillSuperSigs(cls *Class, m *FuncSet) { 438 for _, s := range cls.Supers { 439 sup := j.clsMap[s] 440 if sm, exists := sup.methodMap[m.GoName]; exists { 441 sm.CommonSig = combineSigs(j.clsMap, sm.CommonSig, m.CommonSig) 442 } 443 j.fillSuperSigs(sup, m) 444 } 445 } 446 447 func (v *Var) Constant() bool { 448 return v.Static && v.Final && v.Val != "" 449 } 450 451 // Mangle a name according to 452 // http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp16696 453 // 454 // TODO: Support unicode characters 455 func JNIMangle(s string) string { 456 var m []byte 457 for i := 0; i < len(s); i++ { 458 switch c := s[i]; c { 459 case '.', '/': 460 m = append(m, '_') 461 case '$': 462 m = append(m, "_00024"...) 463 case '_': 464 m = append(m, "_1"...) 465 case ';': 466 m = append(m, "_2"...) 467 case '[': 468 m = append(m, "_3"...) 469 default: 470 m = append(m, c) 471 } 472 } 473 return string(m) 474 } 475 476 func (t *Type) Type() string { 477 switch t.Kind { 478 case Int: 479 return "int" 480 case Boolean: 481 return "boolean" 482 case Short: 483 return "short" 484 case Char: 485 return "char" 486 case Byte: 487 return "byte" 488 case Long: 489 return "long" 490 case Float: 491 return "float" 492 case Double: 493 return "double" 494 case String: 495 return "String" 496 case Array: 497 return t.Elem.Type() + "[]" 498 case Object: 499 return t.Class 500 default: 501 panic("invalid kind") 502 } 503 } 504 505 func (t *Type) JNIType() string { 506 switch t.Kind { 507 case Int: 508 return "jint" 509 case Boolean: 510 return "jboolean" 511 case Short: 512 return "jshort" 513 case Char: 514 return "jchar" 515 case Byte: 516 return "jbyte" 517 case Long: 518 return "jlong" 519 case Float: 520 return "jfloat" 521 case Double: 522 return "jdouble" 523 case String: 524 return "jstring" 525 case Array: 526 return "jarray" 527 case Object: 528 return "jobject" 529 default: 530 panic("invalid kind") 531 } 532 } 533 534 func (t *Type) CType() string { 535 switch t.Kind { 536 case Int, Boolean, Short, Char, Byte, Long, Float, Double: 537 return t.JNIType() 538 case String: 539 return "nstring" 540 case Array: 541 if t.Elem.Kind != Byte { 542 panic("unsupported array type") 543 } 544 return "nbyteslice" 545 case Object: 546 return "jint" 547 default: 548 panic("invalid kind") 549 } 550 } 551 552 func (t *Type) JNICallType() string { 553 switch t.Kind { 554 case Int: 555 return "Int" 556 case Boolean: 557 return "Boolean" 558 case Short: 559 return "Short" 560 case Char: 561 return "Char" 562 case Byte: 563 return "Byte" 564 case Long: 565 return "Long" 566 case Float: 567 return "Float" 568 case Double: 569 return "Double" 570 case String, Object, Array: 571 return "Object" 572 default: 573 panic("invalid kind") 574 } 575 } 576 577 func (j *Importer) filterReferences(classes []*Class, refs *importers.References, funcRefs map[funcRef]struct{}) { 578 for _, cls := range classes { 579 var filtered []*FuncSet 580 for _, f := range cls.Funcs { 581 if _, exists := funcRefs[funcRef{cls.Name, f.GoName}]; exists { 582 filtered = append(filtered, f) 583 } 584 } 585 cls.Funcs = filtered 586 filtered = nil 587 for _, m := range cls.Methods { 588 if _, exists := refs.Names[m.GoName]; exists { 589 filtered = append(filtered, m) 590 } 591 } 592 cls.Methods = filtered 593 } 594 } 595 596 // importClasses imports the named classes from the classpaths of the Importer. 597 func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) { 598 if len(names) == 0 { 599 return nil, nil 600 } 601 args := []string{"-J-Duser.language=en", "-s", "-protected", "-constants"} 602 args = append(args, "-classpath", j.Classpath) 603 //if j.Bootclasspath != "" { 604 // args = append(args, "-bootclasspath", j.Bootclasspath) 605 //} 606 args = append(args, names...) 607 javapPath, err := javapPath() 608 if err != nil { 609 return nil, err 610 } 611 javap := exec.Command(javapPath, args...) 612 out, err := javap.CombinedOutput() 613 if err != nil { 614 if _, ok := err.(*exec.ExitError); !ok { 615 return nil, fmt.Errorf("javap failed: %v", err) 616 } 617 // Not every name is a Java class so an exit error from javap is not 618 // fatal. 619 } 620 s := bufio.NewScanner(bytes.NewBuffer(out)) 621 var classes []*Class 622 for _, name := range names { 623 cls, err := j.scanClass(s, name) 624 if err != nil { 625 _, notfound := err.(*errClsNotFound) 626 if notfound && allowMissingClasses { 627 continue 628 } 629 if notfound && name != "android.databinding.DataBindingComponent" { 630 return nil, err 631 } 632 // The Android Databinding library generates android.databinding.DataBindingComponent 633 // too late in the build process for the gobind plugin to import it. Synthesize a class 634 // for it instead. 635 cls = &Class{ 636 Name: name, 637 FindName: name, 638 Interface: true, 639 PkgName: "databinding", 640 JNIName: JNIMangle(name), 641 } 642 } 643 classes = append(classes, cls) 644 j.clsMap[name] = cls 645 } 646 return classes, nil 647 } 648 649 // importReferencedClasses imports all implicit classes (super types, parameter and 650 // return types) for the given classes not already imported. 651 func (j *Importer) importReferencedClasses(classes []*Class) ([]*Class, error) { 652 var allCls []*Class 653 // Include methods from extended or implemented classes. 654 for { 655 set := make(map[string]struct{}) 656 for _, cls := range classes { 657 j.unknownImplicitClasses(cls, set) 658 } 659 if len(set) == 0 { 660 break 661 } 662 var names []string 663 for n := range set { 664 names = append(names, n) 665 } 666 newCls, err := j.importClasses(names, false) 667 if err != nil { 668 return nil, err 669 } 670 allCls = append(allCls, newCls...) 671 classes = newCls 672 } 673 return allCls, nil 674 } 675 676 func (j *Importer) implicitFuncTypes(f *Func) []string { 677 var unk []string 678 if rt := f.Ret; rt != nil && rt.Kind == Object { 679 unk = append(unk, rt.Class) 680 } 681 for _, t := range f.Params { 682 if t.Kind == Object { 683 unk = append(unk, t.Class) 684 } 685 } 686 return unk 687 } 688 689 func (j *Importer) unknownImplicitClasses(cls *Class, set map[string]struct{}) { 690 for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { 691 for _, fs := range fsets { 692 for _, f := range fs.Funcs { 693 names := j.implicitFuncTypes(f) 694 for _, name := range names { 695 if _, exists := j.clsMap[name]; !exists { 696 set[name] = struct{}{} 697 } 698 } 699 } 700 } 701 } 702 for _, n := range cls.Supers { 703 if s, exists := j.clsMap[n]; exists { 704 j.unknownImplicitClasses(s, set) 705 } else { 706 set[n] = struct{}{} 707 } 708 } 709 } 710 711 func (j *Importer) implicitFuncClasses(funcs []*FuncSet, impl []string) []string { 712 var l []string 713 for _, fs := range funcs { 714 for _, f := range fs.Funcs { 715 if rt := f.Ret; rt != nil && rt.Kind == Object { 716 l = append(l, rt.Class) 717 } 718 for _, t := range f.Params { 719 if t.Kind == Object { 720 l = append(l, t.Class) 721 } 722 } 723 } 724 } 725 return impl 726 } 727 728 func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { 729 if !s.Scan() { 730 return nil, fmt.Errorf("%s: missing javap header", name) 731 } 732 head := s.Text() 733 if errPref := "Error: "; strings.HasPrefix(head, errPref) { 734 msg := head[len(errPref):] 735 if strings.HasPrefix(msg, "class not found: "+name) { 736 return nil, &errClsNotFound{name} 737 } 738 return nil, errors.New(msg) 739 } 740 if !strings.HasPrefix(head, "Compiled from ") { 741 return nil, fmt.Errorf("%s: unexpected header: %s", name, head) 742 } 743 if !s.Scan() { 744 return nil, fmt.Errorf("%s: missing javap class declaration", name) 745 } 746 clsDecl := s.Text() 747 cls, err := j.scanClassDecl(name, clsDecl) 748 if err != nil { 749 return nil, err 750 } 751 cls.JNIName = JNIMangle(cls.Name) 752 clsElems := strings.Split(cls.Name, ".") 753 cls.PkgName = clsElems[len(clsElems)-1] 754 var funcs []*Func 755 for s.Scan() { 756 decl := strings.TrimSpace(s.Text()) 757 if decl == "}" { 758 break 759 } else if decl == "" { 760 continue 761 } 762 if !s.Scan() { 763 return nil, fmt.Errorf("%s: missing descriptor for member %q", name, decl) 764 } 765 desc := strings.TrimSpace(s.Text()) 766 desc = strings.TrimPrefix(desc, "descriptor: ") 767 var static, final, abstract, public bool 768 // Trim modifiders from the declaration. 769 loop: 770 for { 771 idx := strings.Index(decl, " ") 772 if idx == -1 { 773 break 774 } 775 keyword := decl[:idx] 776 switch keyword { 777 case "public": 778 public = true 779 case "protected", "native": 780 // ignore 781 case "static": 782 static = true 783 case "final": 784 final = true 785 case "abstract": 786 abstract = true 787 default: 788 // Hopefully we reached the declaration now. 789 break loop 790 } 791 decl = decl[idx+1:] 792 } 793 // Trim ending ; 794 decl = decl[:len(decl)-1] 795 if idx := strings.Index(decl, "("); idx != -1 { 796 f, err := j.scanMethod(decl, desc, idx) 797 if err != nil { 798 return nil, fmt.Errorf("%s: %v", name, err) 799 } 800 if f != nil { 801 f.Static = static 802 f.Abstract = abstract 803 f.Public = public || cls.Interface 804 f.Final = final 805 f.Constructor = f.Name == cls.FindName 806 if f.Constructor { 807 cls.HasNoArgCon = cls.HasNoArgCon || len(f.Params) == 0 808 f.Public = f.Public && !cls.Abstract 809 f.Name = "new" 810 f.Ret = &Type{Class: name, Kind: Object} 811 } 812 funcs = append(funcs, f) 813 } 814 } else { 815 // Member is a variable 816 v, err := j.scanVar(decl, desc) 817 if err != nil { 818 return nil, fmt.Errorf("%s: %v", name, err) 819 } 820 if v != nil && public { 821 v.Static = static 822 v.Final = final 823 cls.Vars = append(cls.Vars, v) 824 } 825 } 826 } 827 for _, f := range funcs { 828 var m map[string]*FuncSet 829 var l *[]*FuncSet 830 goName := initialUpper(f.Name) 831 if f.Static || f.Constructor { 832 m = cls.funcMap 833 l = &cls.Funcs 834 } else { 835 m = cls.methodMap 836 l = &cls.Methods 837 } 838 fs, exists := m[goName] 839 if !exists { 840 fs = &FuncSet{ 841 Name: f.Name, 842 GoName: goName, 843 } 844 m[goName] = fs 845 *l = append(*l, fs) 846 } 847 fs.Funcs = append(fs.Funcs, f) 848 } 849 return cls, nil 850 } 851 852 func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { 853 isRoot := name == "java.lang.Object" 854 cls := &Class{ 855 Name: name, 856 funcMap: make(map[string]*FuncSet), 857 methodMap: make(map[string]*FuncSet), 858 HasNoArgCon: isRoot, 859 } 860 const ( 861 stMod = iota 862 stName 863 stExt 864 stImpl 865 ) 866 superClsDecl := isRoot 867 st := stMod 868 var w []byte 869 // if > 0, we're inside a generics declaration 870 gennest := 0 871 for i := 0; i < len(decl); i++ { 872 c := decl[i] 873 switch c { 874 default: 875 if gennest == 0 { 876 w = append(w, c) 877 } 878 case '>': 879 gennest-- 880 case '<': 881 gennest++ 882 case '{': 883 if !superClsDecl && !cls.Interface { 884 cls.Supers = append(cls.Supers, "java.lang.Object") 885 } 886 return cls, nil 887 case ' ', ',': 888 if gennest > 0 { 889 break 890 } 891 switch w := string(w); w { 892 default: 893 switch st { 894 case stName: 895 if strings.Replace(w, "$", ".", -1) != strings.Replace(name, "$", ".", -1) { 896 return nil, fmt.Errorf("unexpected name %q in class declaration: %q", w, decl) 897 } 898 cls.FindName = w 899 case stExt: 900 superClsDecl = true 901 cls.Supers = append(cls.Supers, w) 902 case stImpl: 903 if !cls.Interface { 904 cls.Supers = append(cls.Supers, w) 905 } 906 default: 907 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 908 } 909 case "": 910 // skip 911 case "public": 912 if st != stMod { 913 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 914 } 915 case "abstract": 916 if st != stMod { 917 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 918 } 919 cls.Abstract = true 920 case "final": 921 if st != stMod { 922 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 923 } 924 cls.Final = true 925 case "interface": 926 cls.Interface = true 927 fallthrough 928 case "class": 929 if st != stMod { 930 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 931 } 932 st = stName 933 case "extends": 934 if st != stName { 935 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 936 } 937 st = stExt 938 case "implements": 939 if st != stName && st != stExt { 940 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 941 } 942 st = stImpl 943 } 944 w = w[:0] 945 } 946 } 947 return nil, fmt.Errorf("missing ending { in class declaration: %q", decl) 948 } 949 950 func (j *Importer) scanVar(decl, desc string) (*Var, error) { 951 v := new(Var) 952 const eq = " = " 953 idx := strings.Index(decl, eq) 954 if idx != -1 { 955 val, ok := j.parseJavaValue(decl[idx+len(eq):]) 956 if !ok { 957 // Skip constants that cannot be represented in Go 958 return nil, nil 959 } 960 v.Val = val 961 } else { 962 idx = len(decl) 963 } 964 for i := idx - 1; i >= 0; i-- { 965 if i == 0 || decl[i-1] == ' ' { 966 v.Name = decl[i:idx] 967 break 968 } 969 } 970 if v.Name == "" { 971 return nil, fmt.Errorf("unable to parse member name from declaration: %q", decl) 972 } 973 typ, _, err := j.parseJavaType(desc) 974 if err != nil { 975 return nil, fmt.Errorf("invalid type signature for %s: %q", v.Name, desc) 976 } 977 v.Type = typ 978 return v, nil 979 } 980 981 func (j *Importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) { 982 // Member is a method 983 f := new(Func) 984 f.Desc = desc 985 for i := parenIdx - 1; i >= 0; i-- { 986 if i == 0 || decl[i-1] == ' ' { 987 f.Name = decl[i:parenIdx] 988 break 989 } 990 } 991 if f.Name == "" { 992 return nil, fmt.Errorf("unable to parse method name from declaration: %q", decl) 993 } 994 if desc[0] != '(' { 995 return nil, fmt.Errorf("invalid descriptor for method %s: %q", f.Name, desc) 996 } 997 const throws = " throws " 998 if idx := strings.Index(decl, throws); idx != -1 { 999 f.Throws = decl[idx+len(throws):] 1000 } 1001 i := 1 1002 for desc[i] != ')' { 1003 typ, n, err := j.parseJavaType(desc[i:]) 1004 if err != nil { 1005 return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err) 1006 } 1007 i += n 1008 f.Params = append(f.Params, typ) 1009 } 1010 f.ArgDesc = desc[1:i] 1011 i++ // skip ending ) 1012 if desc[i] != 'V' { 1013 typ, _, err := j.parseJavaType(desc[i:]) 1014 if err != nil { 1015 return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err) 1016 } 1017 f.Ret = typ 1018 } 1019 return f, nil 1020 } 1021 1022 func (j *Importer) fillThrowables(classes []*Class) { 1023 thrCls, ok := j.clsMap["java.lang.Throwable"] 1024 if !ok { 1025 // If Throwable isn't in the class map 1026 // no imported class inherits from Throwable 1027 return 1028 } 1029 for _, cls := range classes { 1030 j.fillThrowableFor(cls, thrCls) 1031 } 1032 } 1033 1034 func (j *Importer) fillThrowableFor(cls, thrCls *Class) { 1035 if cls.Interface || cls.Throwable { 1036 return 1037 } 1038 cls.Throwable = cls == thrCls 1039 for _, name := range cls.Supers { 1040 sup := j.clsMap[name] 1041 j.fillThrowableFor(sup, thrCls) 1042 cls.Throwable = cls.Throwable || sup.Throwable 1043 } 1044 } 1045 1046 func commonSig(f *Func) CommonSig { 1047 return CommonSig{ 1048 Params: f.Params, 1049 Ret: f.Ret, 1050 HasRet: f.Ret != nil, 1051 Throws: f.Throws != "", 1052 } 1053 } 1054 1055 func (j *Importer) fillFuncSigs(funcs []*FuncSet) { 1056 for _, fs := range funcs { 1057 var sigs []CommonSig 1058 for _, f := range fs.Funcs { 1059 sigs = append(sigs, commonSig(f)) 1060 } 1061 fs.CommonSig = combineSigs(j.clsMap, sigs...) 1062 } 1063 } 1064 1065 func (j *Importer) fillAllMethods(cls *Class) { 1066 if len(cls.AllMethods) > 0 { 1067 return 1068 } 1069 for _, supName := range cls.Supers { 1070 super := j.clsMap[supName] 1071 j.fillAllMethods(super) 1072 } 1073 var fsets []*FuncSet 1074 fsets = append(fsets, cls.Methods...) 1075 for _, supName := range cls.Supers { 1076 super := j.clsMap[supName] 1077 fsets = append(fsets, super.AllMethods...) 1078 } 1079 sigs := make(map[FuncSig]struct{}) 1080 methods := make(map[string]*FuncSet) 1081 for _, fs := range fsets { 1082 clsFs, exists := methods[fs.Name] 1083 if !exists { 1084 clsFs = &FuncSet{ 1085 Name: fs.Name, 1086 GoName: fs.GoName, 1087 CommonSig: fs.CommonSig, 1088 } 1089 cls.AllMethods = append(cls.AllMethods, clsFs) 1090 methods[fs.Name] = clsFs 1091 } else { 1092 // Combine the (overloaded) signature with the other variants. 1093 clsFs.CommonSig = combineSigs(j.clsMap, clsFs.CommonSig, fs.CommonSig) 1094 } 1095 for _, f := range fs.Funcs { 1096 if _, exists := sigs[f.FuncSig]; exists { 1097 continue 1098 } 1099 sigs[f.FuncSig] = struct{}{} 1100 clsFs.Funcs = append(clsFs.Funcs, f) 1101 } 1102 } 1103 } 1104 1105 func (j *Importer) parseJavaValue(v string) (string, bool) { 1106 v = strings.TrimRight(v, "ldf") 1107 switch v { 1108 case "", "NaN", "Infinity", "-Infinity": 1109 return "", false 1110 default: 1111 if v[0] == '\'' { 1112 // Skip character constants, since they can contain invalid code points 1113 // that are unacceptable to Go. 1114 return "", false 1115 } 1116 return v, true 1117 } 1118 } 1119 1120 func (j *Importer) parseJavaType(desc string) (*Type, int, error) { 1121 t := new(Type) 1122 var n int 1123 if desc == "" { 1124 return t, n, errors.New("empty type signature") 1125 } 1126 n++ 1127 switch desc[0] { 1128 case 'Z': 1129 t.Kind = Boolean 1130 case 'B': 1131 t.Kind = Byte 1132 case 'C': 1133 t.Kind = Char 1134 case 'S': 1135 t.Kind = Short 1136 case 'I': 1137 t.Kind = Int 1138 case 'J': 1139 t.Kind = Long 1140 case 'F': 1141 t.Kind = Float 1142 case 'D': 1143 t.Kind = Double 1144 case 'L': 1145 var clsName string 1146 for i := n; i < len(desc); i++ { 1147 if desc[i] == ';' { 1148 clsName = strings.Replace(desc[n:i], "/", ".", -1) 1149 clsName = strings.Replace(clsName, "$", ".", -1) 1150 n += i - n + 1 1151 break 1152 } 1153 } 1154 if clsName == "" { 1155 return t, n, errors.New("missing ; in class type signature") 1156 } 1157 if clsName == "java.lang.String" { 1158 t.Kind = String 1159 } else { 1160 t.Kind = Object 1161 t.Class = clsName 1162 } 1163 case '[': 1164 et, n2, err := j.parseJavaType(desc[n:]) 1165 if err != nil { 1166 return t, n, err 1167 } 1168 n += n2 1169 t.Kind = Array 1170 t.Elem = et 1171 default: 1172 return t, n, fmt.Errorf("invalid type signature: %s", desc) 1173 } 1174 return t, n, nil 1175 } 1176 1177 func initialUpper(s string) string { 1178 if s == "" { 1179 return "" 1180 } 1181 r, n := utf8.DecodeRuneInString(s) 1182 return string(unicode.ToUpper(r)) + s[n:] 1183 }