2
0
mirror of synced 2025-02-23 23:08:14 +00:00

mobile/bind: handle null references from Java in Go

The Seq Java class has a special case for null references. Expand
the special case to Go so that null references from Java are properly
translated to nil.

Fixes golang/go#14228

Change-Id: I915d1f843c9db299d6910480f6d10dae0121a3b4
Reviewed-on: https://go-review.googlesource.com/19460
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur 2016-02-11 14:09:24 +01:00 committed by David Crawshaw
parent 46f9e01d1e
commit d1c2f486a3
12 changed files with 35 additions and 14 deletions

View File

@ -352,7 +352,7 @@ func (g *goGen) genRead(valName, seqName string, typ types.Type) {
g.Printf("if %s_ref.Num < 0 { // go object \n", valName) g.Printf("if %s_ref.Num < 0 { // go object \n", valName)
g.Printf(" %s = %s_ref.Get().(%s.%s)\n", valName, valName, g.pkg.Name(), o.Name()) g.Printf(" %s = %s_ref.Get().(%s.%s)\n", valName, valName, g.pkg.Name(), o.Name())
if hasProxy { if hasProxy {
g.Printf("} else { // foreign object \n") g.Printf("} else if %s_ref.Num != seq.NullRefNum { // foreign object \n", valName)
g.Printf(" %s = (*proxy%s)(%s_ref)\n", valName, o.Name(), valName) g.Printf(" %s = (*proxy%s)(%s_ref)\n", valName, o.Name(), valName)
} }
g.Printf("}\n") g.Printf("}\n")

View File

@ -77,6 +77,8 @@ public class Seq {
public native void writeByteArray(byte[] v); public native void writeByteArray(byte[] v);
public void writeRef(Ref ref) { public void writeRef(Ref ref) {
if (ref == null)
ref = RefTracker.nullRef;
tracker.inc(ref); tracker.inc(ref);
writeInt32(ref.refnum); writeInt32(ref.refnum);
} }
@ -172,9 +174,10 @@ public class Seq {
static final class RefTracker { static final class RefTracker {
private static final int REF_OFFSET = 42; private static final int REF_OFFSET = 42;
private static final int NULL_REFNUM = 41; // also known to bind/seq/ref.go
// use single Ref for null Seq.Object // use single Ref for null Seq.Object
private static final Ref nullRef = new Ref(REF_OFFSET - 1, null); private static final Ref nullRef = new Ref(NULL_REFNUM, null);
// Next Java object reference number. // Next Java object reference number.
// //

View File

@ -381,4 +381,12 @@ public class SeqTest extends AndroidTestCase {
String got = n.getErr(); String got = n.getErr();
assertEquals("want back the error message we set", want, got); assertEquals("want back the error message we set", want, got);
} }
public void testNullReferences() {
assertTrue(Testpkg.CallWithNull(null, new Testpkg.NullTest.Stub() {
public Testpkg.NullTest Null() {
return null;
}
}));
}
} }

View File

@ -204,3 +204,11 @@ func ReadAsset() string {
} }
return string(b) return string(b)
} }
type NullTest interface {
Null() NullTest
}
func CallWithNull(_null NullTest, nuller NullTest) bool {
return _null == nil && nuller.Null() == nil
}

View File

@ -81,7 +81,7 @@ func seqWrite(o types.Type, name string) string {
t := seqType(o) t := seqType(o)
if t == "Ref" { if t == "Ref" {
// TODO(crawshaw): do something cleaner, i.e. genWrite. // TODO(crawshaw): do something cleaner, i.e. genWrite.
return t + "(" + name + ".ref())" return t + "(" + name + " != null ? " + name + ".ref() : null)"
} }
return t + "(" + name + ")" return t + "(" + name + ")"
} }

View File

@ -19,6 +19,8 @@ type countedObj struct {
cnt int32 cnt int32
} }
const NullRefNum = 41 // also known to bind/java/Seq.java
// refs stores Go objects that have been passed to another language. // refs stores Go objects that have been passed to another language.
var refs struct { var refs struct {
sync.Mutex sync.Mutex

View File

@ -14,7 +14,7 @@ func proxy_Add3(out, in *seq.Buffer) {
param_r_ref := in.ReadRef() param_r_ref := in.ReadRef()
if param_r_ref.Num < 0 { // go object if param_r_ref.Num < 0 { // go object
param_r = param_r_ref.Get().(interfaces.I) param_r = param_r_ref.Get().(interfaces.I)
} else { // foreign object } else if param_r_ref.Num != seq.NullRefNum { // foreign object
param_r = (*proxyI)(param_r_ref) param_r = (*proxyI)(param_r_ref)
} }
res := interfaces.Add3(param_r) res := interfaces.Add3(param_r)
@ -26,7 +26,7 @@ func proxy_CallErr(out, in *seq.Buffer) {
param_e_ref := in.ReadRef() param_e_ref := in.ReadRef()
if param_e_ref.Num < 0 { // go object if param_e_ref.Num < 0 { // go object
param_e = param_e_ref.Get().(interfaces.Error) param_e = param_e_ref.Get().(interfaces.Error)
} else { // foreign object } else if param_e_ref.Num != seq.NullRefNum { // foreign object
param_e = (*proxyError)(param_e_ref) param_e = (*proxyError)(param_e_ref)
} }
err := interfaces.CallErr(param_e) err := interfaces.CallErr(param_e)

View File

@ -15,7 +15,7 @@ public abstract class Interfaces {
_out = new go.Seq(); _out = new go.Seq();
int _result; int _result;
_in = new go.Seq(); _in = new go.Seq();
_in.writeRef(r.ref()); _in.writeRef(r != null ? r.ref() : null);
Seq.send(DESCRIPTOR, CALL_Add3, _in, _out); Seq.send(DESCRIPTOR, CALL_Add3, _in, _out);
_result = _out.readInt32(); _result = _out.readInt32();
return _result; return _result;
@ -26,7 +26,7 @@ public abstract class Interfaces {
go.Seq _out = null; go.Seq _out = null;
_out = new go.Seq(); _out = new go.Seq();
_in = new go.Seq(); _in = new go.Seq();
_in.writeRef(e.ref()); _in.writeRef(e != null ? e.ref() : null);
Seq.send(DESCRIPTOR, CALL_CallErr, _in, _out); Seq.send(DESCRIPTOR, CALL_CallErr, _in, _out);
String _err = _out.readString(); String _err = _out.readString();
if (_err != null && !_err.isEmpty()) { if (_err != null && !_err.isEmpty()) {
@ -222,7 +222,7 @@ public abstract class Interfaces {
switch (code) { switch (code) {
case Proxy.CALL_F: { case Proxy.CALL_F: {
I1 result = this.F(); I1 result = this.F();
out.writeRef(result.ref()); out.writeRef(result != null ? result.ref() : null);
return; return;
} }
default: default:

View File

@ -66,7 +66,7 @@ public abstract class Issue10788 {
go.Seq _out = null; go.Seq _out = null;
_in = new go.Seq(); _in = new go.Seq();
_in.writeRef(ref); _in.writeRef(ref);
_in.writeRef(s.ref()); _in.writeRef(s != null ? s.ref() : null);
Seq.send(DESCRIPTOR, CALL_DoSomeWork, _in, _out); Seq.send(DESCRIPTOR, CALL_DoSomeWork, _in, _out);
} }

View File

@ -65,7 +65,7 @@ public abstract class Structs {
_out = new go.Seq(); _out = new go.Seq();
S _result; S _result;
_in = new go.Seq(); _in = new go.Seq();
_in.writeRef(s.ref()); _in.writeRef(s != null ? s.ref() : null);
Seq.send(DESCRIPTOR, CALL_Identity, _in, _out); Seq.send(DESCRIPTOR, CALL_Identity, _in, _out);
_result = new S(_out.readRef()); _result = new S(_out.readRef());
return _result; return _result;
@ -77,7 +77,7 @@ public abstract class Structs {
_out = new go.Seq(); _out = new go.Seq();
S _result; S _result;
_in = new go.Seq(); _in = new go.Seq();
_in.writeRef(s.ref()); _in.writeRef(s != null ? s.ref() : null);
Seq.send(DESCRIPTOR, CALL_IdentityWithError, _in, _out); Seq.send(DESCRIPTOR, CALL_IdentityWithError, _in, _out);
_result = new S(_out.readRef()); _result = new S(_out.readRef());
String _err = _out.readString(); String _err = _out.readString();

View File

@ -93,7 +93,7 @@ func var_setAnInterface(out, in *seq.Buffer) {
v_ref := in.ReadRef() v_ref := in.ReadRef()
if v_ref.Num < 0 { // go object if v_ref.Num < 0 { // go object
v = v_ref.Get().(vars.I) v = v_ref.Get().(vars.I)
} else { // foreign object } else if v_ref.Num != seq.NullRefNum { // foreign object
v = (*proxyI)(v_ref) v = (*proxyI)(v_ref)
} }
vars.AnInterface = v vars.AnInterface = v

View File

@ -76,7 +76,7 @@ public abstract class Vars {
public static void setAStructPtr(S v) { public static void setAStructPtr(S v) {
Seq in = new Seq(); Seq in = new Seq();
in.writeRef(v.ref()); in.writeRef(v != null ? v.ref() : null);
Seq.send("vars.AStructPtr", 1, in, null); Seq.send("vars.AStructPtr", 1, in, null);
} }
@ -154,7 +154,7 @@ public abstract class Vars {
public static void setAnInterface(I v) { public static void setAnInterface(I v) {
Seq in = new Seq(); Seq in = new Seq();
in.writeRef(v.ref()); in.writeRef(v != null ? v.ref() : null);
Seq.send("vars.AnInterface", 1, in, null); Seq.send("vars.AnInterface", 1, in, null);
} }