2
0
mirror of synced 2025-02-23 06:48:15 +00:00

bind: generate reverse bindings for implicit Java types

Before this CL, Java types that were only implicitly referenced
were represented as interface{}. However, if a value of such an
implicit type were passed to Java, a runtime crash would occur
because there would be no wrapper class to unwrap.

Fix this by generating implicit types, fixing the crashes,
gaining type safety, and removing the interface{} special case in
the generator.

While we're here, remove a redundant insert to the clsMap map in
java.go.

Change-Id: Ic50125da3d7cd6075899bf628d419b084c630490
Reviewed-on: https://go-review.googlesource.com/34777
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur 2017-01-01 19:55:42 +01:00
parent ff6f6e8d8e
commit fe0977739a
8 changed files with 280 additions and 36 deletions

View File

@ -84,9 +84,6 @@ func (g *ClassGen) goType(t *java.Type, local bool) string {
case java.Array:
return "[]" + g.goType(t.Elem, local)
case java.Object:
if _, exists := g.imported[t.Class]; !exists {
return "interface{}"
}
name := goClsName(t.Class)
if !local {
name = "Java." + name

View File

@ -114,12 +114,6 @@ public class ClassesTest extends InstrumentationTestCase {
assertEquals("IOException message", Javapkg.IOExceptionMessage, exc.getMessage());
}
public void testUnknownType() {
GoObject o = new GoObject();
o.toString(); // Set this
assertTrue("GoObject.getClass not null", o.checkClass());
}
public void testInnerClass() {
Character.Subset s = new Character.Subset(""){};
Character.Subset s2 = new GoSubset("");

View File

@ -8,6 +8,7 @@ import (
gopkg "Java/go/java"
"Java/java/io"
"Java/java/lang"
"Java/java/lang/System"
"Java/java/util/Spliterators"
"Java/java/util/concurrent"
)
@ -52,3 +53,9 @@ func innerClassTypes() {
// for the return value as well as parameters.
Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2(nil)
}
func returnType() {
// Implicit types (java.io.Console) should be wrapped.
cons := System.Console()
cons.Flush()
}

View File

@ -27,6 +27,9 @@ type Java_util_concurrent_TimeUnit interface {
type Java_util_Spliterators interface {
}
type Java_lang_System interface {
}
type Go_java_Future interface {
Get() (Java_lang_Object, error)
Get2(a0 int64, a1 Java_util_concurrent_TimeUnit) (Java_lang_Object, error)
@ -47,6 +50,16 @@ type Go_java_Runnable interface {
Super() Go_java_Runnable
}
type Java_util_PrimitiveIterator_OfInt interface {
}
type Java_util_Spliterator_OfInt interface {
}
type Java_io_Console interface {
Flush() error
}
// File is generated by gobind. Do not edit.
package gomobile_bind
@ -70,10 +83,14 @@ import "Java/java/util/concurrent/Future"
import "Java/java/lang/Object"
import "Java/java/util/concurrent/TimeUnit"
import "Java/java/util/Spliterators"
import "Java/java/lang/System"
import "Java/go/java/Future"
import "Java/go/java/InputStream"
import "Java/go/java/Object"
import "Java/go/java/Runnable"
import "Java/java/util/PrimitiveIterator/OfInt"
import "Java/java/util/Spliterator/OfInt"
import "Java/java/io/Console"
import "unsafe"
import "reflect"
@ -96,10 +113,14 @@ func initClasses() {
init_java_lang_Object()
init_java_util_concurrent_TimeUnit()
init_java_util_Spliterators()
init_java_lang_System()
init_go_java_Future()
init_go_java_InputStream()
init_go_java_Object()
init_go_java_Runnable()
init_java_util_PrimitiveIterator_OfInt()
init_java_util_Spliterator_OfInt()
init_java_io_Console()
}
var class_java_lang_Runnable C.jclass
@ -324,19 +345,19 @@ func init_java_util_Spliterators() {
C.free(unsafe.Pointer(fn))
C.free(unsafe.Pointer(fd))
if m != nil {
Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2 = func(a0 interface{}) interface{} {
Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2 = func(a0 Java.Java_util_Spliterator_OfInt) Java.Java_util_PrimitiveIterator_OfInt {
var _a0 C.jint = _seq.NullRefNum
if a0 != nil {
_a0 = C.jint(_seq.ToRefNum(a0))
}
res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(clazz, m, _a0)
var _res interface{}
var _res Java.Java_util_PrimitiveIterator_OfInt
_res_ref := _seq.FromRefNum(int32(res.res))
if _res_ref != nil {
if res.res < 0 { // go object
_res = _res_ref.Get().(interface{})
_res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfInt)
} else { // foreign object
_res = _res_ref
_res = (*proxy_class_java_util_PrimitiveIterator_OfInt)(_res_ref)
}
}
var _exc error
@ -368,6 +389,63 @@ type proxy_class_java_util_Spliterators _seq.Ref
func (p *proxy_class_java_util_Spliterators) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
var class_java_lang_System C.jclass
func init_java_lang_System() {
cls := C.CString("java/lang/System")
clazz := C.go_seq_find_class(cls)
C.free(unsafe.Pointer(cls))
if clazz == nil {
return
}
class_java_lang_System = clazz
{
fn := C.CString("console")
fd := C.CString("()Ljava/io/Console;")
m := C.go_seq_get_static_method_id(clazz, fn, fd)
C.free(unsafe.Pointer(fn))
C.free(unsafe.Pointer(fd))
if m != nil {
System.Console = func() Java.Java_io_Console {
res := C.cproxy_s_java_lang_System_console(clazz, m)
var _res Java.Java_io_Console
_res_ref := _seq.FromRefNum(int32(res.res))
if _res_ref != nil {
if res.res < 0 { // go object
_res = _res_ref.Get().(Java.Java_io_Console)
} else { // foreign object
_res = (*proxy_class_java_io_Console)(_res_ref)
}
}
var _exc error
_exc_ref := _seq.FromRefNum(int32(res.exc))
if _exc_ref != nil {
if res.exc < 0 { // go object
_exc = _exc_ref.Get().(error)
} else { // foreign object
_exc = (*proxy_error)(_exc_ref)
}
}
if (_exc != nil) { panic(_exc) }
return _res
}
}
}
System.Cast = func(v interface{}) Java.Java_lang_System {
t := reflect.TypeOf((*proxy_class_java_lang_System)(nil))
cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_System)
ref := C.jint(_seq.ToRefNum(cv))
if C.go_seq_isinstanceof(ref, class_java_lang_System) != 1 {
panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.System"))
}
return cv
}
}
type proxy_class_java_lang_System _seq.Ref
func (p *proxy_class_java_lang_System) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
var class_go_java_Future C.jclass
func init_go_java_Future() {
@ -652,6 +730,95 @@ func (p *super_go_java_Runnable) Run() {
if (_exc != nil) { panic(_exc) }
}
var class_java_util_PrimitiveIterator_OfInt C.jclass
func init_java_util_PrimitiveIterator_OfInt() {
cls := C.CString("java/util/PrimitiveIterator$OfInt")
clazz := C.go_seq_find_class(cls)
C.free(unsafe.Pointer(cls))
if clazz == nil {
return
}
class_java_util_PrimitiveIterator_OfInt = clazz
OfInt.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfInt {
t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfInt)(nil))
cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfInt)
ref := C.jint(_seq.ToRefNum(cv))
if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfInt) != 1 {
panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfInt"))
}
return cv
}
}
type proxy_class_java_util_PrimitiveIterator_OfInt _seq.Ref
func (p *proxy_class_java_util_PrimitiveIterator_OfInt) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
var class_java_util_Spliterator_OfInt C.jclass
func init_java_util_Spliterator_OfInt() {
cls := C.CString("java/util/Spliterator$OfInt")
clazz := C.go_seq_find_class(cls)
C.free(unsafe.Pointer(cls))
if clazz == nil {
return
}
class_java_util_Spliterator_OfInt = clazz
OfInt.Cast = func(v interface{}) Java.Java_util_Spliterator_OfInt {
t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfInt)(nil))
cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfInt)
ref := C.jint(_seq.ToRefNum(cv))
if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfInt) != 1 {
panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfInt"))
}
return cv
}
}
type proxy_class_java_util_Spliterator_OfInt _seq.Ref
func (p *proxy_class_java_util_Spliterator_OfInt) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
var class_java_io_Console C.jclass
func init_java_io_Console() {
cls := C.CString("java/io/Console")
clazz := C.go_seq_find_class(cls)
C.free(unsafe.Pointer(cls))
if clazz == nil {
return
}
class_java_io_Console = clazz
Console.Cast = func(v interface{}) Java.Java_io_Console {
t := reflect.TypeOf((*proxy_class_java_io_Console)(nil))
cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_io_Console)
ref := C.jint(_seq.ToRefNum(cv))
if C.go_seq_isinstanceof(ref, class_java_io_Console) != 1 {
panic(fmt.Errorf("%T is not an instance of %s", v, "java.io.Console"))
}
return cv
}
}
type proxy_class_java_io_Console _seq.Ref
func (p *proxy_class_java_io_Console) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
func (p *proxy_class_java_io_Console) Flush() error {
res := C.cproxy_java_io_Console_flush(C.jint(p.Bind_proxy_refnum__()))
var _exc error
_exc_ref := _seq.FromRefNum(int32(res))
if _exc_ref != nil {
if res < 0 { // go object
_exc = _exc_ref.Get().(error)
} else { // foreign object
_exc = (*proxy_error)(_exc_ref)
}
}
return _exc
}
// Package gomobile_bind is an autogenerated binder stub for package java.
// gobind -lang=go classes
//

View File

@ -29,6 +29,21 @@ ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024O
}
static jclass class_java_util_Spliterators;
ret_jint cproxy_s_java_lang_System_console(jclass clazz, jmethodID m) {
JNIEnv *env = go_seq_push_local_frame(0);
jobject res = (*env)->CallStaticObjectMethod(env, clazz, m);
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 jclass class_go_java_Future;
static jclass sclass_go_java_Future;
static jmethodID m_go_java_Future_get__;
@ -45,9 +60,13 @@ static jclass class_go_java_Runnable;
static jclass sclass_go_java_Runnable;
static jmethodID m_go_java_Runnable_run;
static jmethodID sm_go_java_Runnable_run;
static jclass class_java_util_PrimitiveIterator_OfInt;
static jclass class_java_util_Spliterator_OfInt;
static jclass class_java_io_Console;
static jmethodID m_java_io_Console_flush;
void init_proxies() {
JNIEnv *env = go_seq_push_local_frame(10);
JNIEnv *env = go_seq_push_local_frame(14);
jclass clazz;
clazz = (*env)->FindClass(env, "java/lang/Runnable");
class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz);
@ -65,6 +84,8 @@ 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);
clazz = (*env)->FindClass(env, "java/lang/System");
class_java_lang_System = (*env)->NewGlobalRef(env, clazz);
clazz = (*env)->FindClass(env, "go/java/Future");
class_go_java_Future = (*env)->NewGlobalRef(env, clazz);
sclass_go_java_Future = (*env)->GetSuperclass(env, clazz);
@ -89,6 +110,13 @@ void init_proxies() {
sclass_go_java_Runnable = (*env)->NewGlobalRef(env, sclass_go_java_Runnable);
m_go_java_Runnable_run = go_seq_get_method_id(clazz, "run", "()V");
sm_go_java_Runnable_run = go_seq_get_method_id(sclass_go_java_Runnable, "run", "()V");
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/io/Console");
class_java_io_Console = (*env)->NewGlobalRef(env, clazz);
m_java_io_Console_flush = go_seq_get_method_id(clazz, "flush", "()V");
go_seq_pop_local_frame(env);
}
@ -275,6 +303,17 @@ jint csuper_go_java_Runnable_run(jint this) {
return _exc_ref;
}
jint cproxy_java_io_Console_flush(jint this) {
JNIEnv *env = go_seq_push_local_frame(1);
// Must be a Java object
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
(*env)->CallVoidMethod(env, _this, m_java_io_Console_flush);
jobject _exc = go_seq_get_exception(env);
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
go_seq_pop_local_frame(env);
return _exc_ref;
}
// JNI functions for the Go <=> Java bridge.
// gobind -lang=java classes
//

View File

@ -58,7 +58,9 @@ extern ret_jint cproxy_go_java_InputStream_read__(jint this);
extern ret_jint csuper_go_java_InputStream_read__(jint this);
extern jint cproxy_go_java_Runnable_run(jint this);
extern jint csuper_go_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_00024OfInt_2(jclass clazz, jmethodID m, jint a0);
extern ret_jint cproxy_s_java_lang_System_console(jclass clazz, jmethodID m);
// JNI function headers for the Go <=> Java bridge.
// gobind -lang=java classes
//

View File

@ -92,14 +92,6 @@ func (o *GoObject) ToString(this gopkg.GoObject) string {
return ToStringPrefix + this.Super().ToString()
}
func (r *GoObject) CheckClass() bool {
// Verify that GetClass returns interface{} because java.lang.Class
// is unreferenced.
var f func() interface{} = r.this.GetClass
// But it should return a value
return f() != nil
}
func (_ *GoObject) HashCode() int32 {
return 42
}

View File

@ -196,16 +196,52 @@ 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 {
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)
}
}
}
}
}
imports, err := j.importClasses(impNames, false)
if err != nil {
return nil, err
}
impClasses = append(impClasses, imports...)
j.initClasses(impClasses, refs)
classes = append(classes, impClasses...)
newClasses = impClasses
}
j.fillThrowables(classes)
return classes, nil
}
func (j *Importer) initClasses(classes []*Class, refs *importers.References) {
for _, cls := range classes {
j.fillAllMethods(cls)
}
j.fillThrowables()
for _, cls := range classes {
j.mangleOverloads(cls.AllMethods)
j.mangleOverloads(cls.Funcs)
}
j.filterReferences(classes, refs)
return classes, nil
}
func (v *Var) Constant() bool {
@ -411,7 +447,7 @@ func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*C
classes = append(classes, cls)
j.clsMap[name] = cls
}
// Include the methods from classes extended or implemented
// Include methods from extended or implemented classes.
unkCls := classes
for {
var unknown []string
@ -425,14 +461,24 @@ func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*C
if err != nil {
return nil, err
}
for _, cls := range newCls {
j.clsMap[cls.Name] = cls
}
unkCls = newCls
}
return classes, nil
}
func (j *Importer) implicitFuncTypes(f *Func) []string {
var unk []string
if rt := f.Ret; rt != nil && rt.Kind == Object {
unk = append(unk, rt.Class)
}
for _, t := range f.Params {
if t.Kind == Object {
unk = append(unk, t.Class)
}
}
return unk
}
func (j *Importer) unknownSuperClasses(cls *Class, unk []string) []string {
loop:
for _, n := range cls.Supers {
@ -727,14 +773,14 @@ func (j *Importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) {
return f, nil
}
func (j *Importer) fillThrowables() {
func (j *Importer) fillThrowables(classes []*Class) {
thrCls, ok := j.clsMap["java.lang.Throwable"]
if !ok {
// If Throwable isn't in the class map
// no imported class inherits from Throwable
return
}
for _, cls := range j.clsMap {
for _, cls := range classes {
j.fillThrowableFor(cls, thrCls)
}
}
@ -769,10 +815,7 @@ func (j *Importer) fillAllMethods(cls *Class) {
for _, f := range super.AllMethods {
if _, exists := methods[f.FuncSig]; !exists {
methods[f.FuncSig] = struct{}{}
// Copy function so each class can have its own
// JNI name mangling.
cpf := *f
cls.AllMethods = append(cls.AllMethods, &cpf)
cls.AllMethods = append(cls.AllMethods, f)
}
}
}
@ -788,8 +831,11 @@ func (j *Importer) fillAllMethods(cls *Class) {
// the method signature is appended in JNI mangled form.
func (j *Importer) mangleOverloads(allFuncs []*Func) {
overloads := make(map[string][]*Func)
for _, f := range allFuncs {
overloads[f.Name] = append(overloads[f.Name], f)
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 {