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:
parent
46f9e01d1e
commit
d1c2f486a3
@ -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(" %s = %s_ref.Get().(%s.%s)\n", valName, valName, g.pkg.Name(), o.Name())
|
||||
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("}\n")
|
||||
|
@ -77,6 +77,8 @@ public class Seq {
|
||||
public native void writeByteArray(byte[] v);
|
||||
|
||||
public void writeRef(Ref ref) {
|
||||
if (ref == null)
|
||||
ref = RefTracker.nullRef;
|
||||
tracker.inc(ref);
|
||||
writeInt32(ref.refnum);
|
||||
}
|
||||
@ -172,9 +174,10 @@ public class Seq {
|
||||
|
||||
static final class RefTracker {
|
||||
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
|
||||
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.
|
||||
//
|
||||
|
@ -381,4 +381,12 @@ public class SeqTest extends AndroidTestCase {
|
||||
String got = n.getErr();
|
||||
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;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -204,3 +204,11 @@ func ReadAsset() string {
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
type NullTest interface {
|
||||
Null() NullTest
|
||||
}
|
||||
|
||||
func CallWithNull(_null NullTest, nuller NullTest) bool {
|
||||
return _null == nil && nuller.Null() == nil
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func seqWrite(o types.Type, name string) string {
|
||||
t := seqType(o)
|
||||
if t == "Ref" {
|
||||
// TODO(crawshaw): do something cleaner, i.e. genWrite.
|
||||
return t + "(" + name + ".ref())"
|
||||
return t + "(" + name + " != null ? " + name + ".ref() : null)"
|
||||
}
|
||||
return t + "(" + name + ")"
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ type countedObj struct {
|
||||
cnt int32
|
||||
}
|
||||
|
||||
const NullRefNum = 41 // also known to bind/java/Seq.java
|
||||
|
||||
// refs stores Go objects that have been passed to another language.
|
||||
var refs struct {
|
||||
sync.Mutex
|
||||
|
4
bind/testdata/interfaces.go.golden
vendored
4
bind/testdata/interfaces.go.golden
vendored
@ -14,7 +14,7 @@ func proxy_Add3(out, in *seq.Buffer) {
|
||||
param_r_ref := in.ReadRef()
|
||||
if param_r_ref.Num < 0 { // go object
|
||||
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)
|
||||
}
|
||||
res := interfaces.Add3(param_r)
|
||||
@ -26,7 +26,7 @@ func proxy_CallErr(out, in *seq.Buffer) {
|
||||
param_e_ref := in.ReadRef()
|
||||
if param_e_ref.Num < 0 { // go object
|
||||
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)
|
||||
}
|
||||
err := interfaces.CallErr(param_e)
|
||||
|
6
bind/testdata/interfaces.java.golden
vendored
6
bind/testdata/interfaces.java.golden
vendored
@ -15,7 +15,7 @@ public abstract class Interfaces {
|
||||
_out = new go.Seq();
|
||||
int _result;
|
||||
_in = new go.Seq();
|
||||
_in.writeRef(r.ref());
|
||||
_in.writeRef(r != null ? r.ref() : null);
|
||||
Seq.send(DESCRIPTOR, CALL_Add3, _in, _out);
|
||||
_result = _out.readInt32();
|
||||
return _result;
|
||||
@ -26,7 +26,7 @@ public abstract class Interfaces {
|
||||
go.Seq _out = null;
|
||||
_out = 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);
|
||||
String _err = _out.readString();
|
||||
if (_err != null && !_err.isEmpty()) {
|
||||
@ -222,7 +222,7 @@ public abstract class Interfaces {
|
||||
switch (code) {
|
||||
case Proxy.CALL_F: {
|
||||
I1 result = this.F();
|
||||
out.writeRef(result.ref());
|
||||
out.writeRef(result != null ? result.ref() : null);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
2
bind/testdata/issue10788.java.golden
vendored
2
bind/testdata/issue10788.java.golden
vendored
@ -66,7 +66,7 @@ public abstract class Issue10788 {
|
||||
go.Seq _out = null;
|
||||
_in = new go.Seq();
|
||||
_in.writeRef(ref);
|
||||
_in.writeRef(s.ref());
|
||||
_in.writeRef(s != null ? s.ref() : null);
|
||||
Seq.send(DESCRIPTOR, CALL_DoSomeWork, _in, _out);
|
||||
}
|
||||
|
||||
|
4
bind/testdata/structs.java.golden
vendored
4
bind/testdata/structs.java.golden
vendored
@ -65,7 +65,7 @@ public abstract class Structs {
|
||||
_out = new go.Seq();
|
||||
S _result;
|
||||
_in = new go.Seq();
|
||||
_in.writeRef(s.ref());
|
||||
_in.writeRef(s != null ? s.ref() : null);
|
||||
Seq.send(DESCRIPTOR, CALL_Identity, _in, _out);
|
||||
_result = new S(_out.readRef());
|
||||
return _result;
|
||||
@ -77,7 +77,7 @@ public abstract class Structs {
|
||||
_out = new go.Seq();
|
||||
S _result;
|
||||
_in = new go.Seq();
|
||||
_in.writeRef(s.ref());
|
||||
_in.writeRef(s != null ? s.ref() : null);
|
||||
Seq.send(DESCRIPTOR, CALL_IdentityWithError, _in, _out);
|
||||
_result = new S(_out.readRef());
|
||||
String _err = _out.readString();
|
||||
|
2
bind/testdata/vars.go.golden
vendored
2
bind/testdata/vars.go.golden
vendored
@ -93,7 +93,7 @@ func var_setAnInterface(out, in *seq.Buffer) {
|
||||
v_ref := in.ReadRef()
|
||||
if v_ref.Num < 0 { // go object
|
||||
v = v_ref.Get().(vars.I)
|
||||
} else { // foreign object
|
||||
} else if v_ref.Num != seq.NullRefNum { // foreign object
|
||||
v = (*proxyI)(v_ref)
|
||||
}
|
||||
vars.AnInterface = v
|
||||
|
4
bind/testdata/vars.java.golden
vendored
4
bind/testdata/vars.java.golden
vendored
@ -76,7 +76,7 @@ public abstract class Vars {
|
||||
|
||||
public static void setAStructPtr(S v) {
|
||||
Seq in = new Seq();
|
||||
in.writeRef(v.ref());
|
||||
in.writeRef(v != null ? v.ref() : null);
|
||||
Seq.send("vars.AStructPtr", 1, in, null);
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ public abstract class Vars {
|
||||
|
||||
public static void setAnInterface(I v) {
|
||||
Seq in = new Seq();
|
||||
in.writeRef(v.ref());
|
||||
in.writeRef(v != null ? v.ref() : null);
|
||||
Seq.send("vars.AnInterface", 1, in, null);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user