What's the right way to evaluate nil returned values from Go functions in Android Java?
Here's what I've tried:
// ExportedGoFunction returns a pointer to a GoStruct or nil in case of fail
func ExportedGoFunction() *GoStruct {
return nil
}
Then I generate a .aar file via gomobile using:
gomobile bind -v --target=android
In my Java code I tried to evaluate nil as null but it's not working. Java Code:
GoLibrary.GoStruct goStruct = GoLibrary.ExportedGoFunction();
if (goStruct != null) {
// This block should not be executed, but it is
Log.d("GoLog", "goStruct is not null");
}
Disclaimer: Other methods from the go library work flawless
For possible future reference, as of 09/2015 I've come up with two ways of dealing with the problem.
The first one is to return an error from the Go code and try/catch-ing the error in Java. Here's an example:
// ExportedGoFunction returns a pointer to a GoStruct or nil in case of fail
func ExportedGoFunction() (*GoStruct, error) {
result := myUnexportedGoStruct()
if result == nil {
return nil, errors.New("Error: GoStruct is Nil")
}
return result, nil
}
And then try/catch the error in Java
try {
GoLibrary.GoStruct myStruct = GoLibrary.ExportedGoFunction();
}
catch (Exception e) {
e.printStackTrace(); // myStruct is nil
}
This approach is both idiomatic Go and Java, but even if it works on preventing the program to crash, it ends up bloating the code with try/catch statements and causing yet more overhead.
So, based on user @SnoProblem answers the non-idiomatic way of solving it and properly handle null values I came up with was:
// NullGoStruct returns false if value is nil or true otherwise
func NullGoStruct(value *GoStruct) bool {
return (value == nil)
}
And then check the code in Java like:
GoLibrary.GoStruct value = GoLibrary.ExportedGoFunction();
if (GoLibrary.NullGoStruct(value)) {
// This block is executed only if value has nil value in Go
Log.d("GoLog", "value is null");
}
Looking through the testing package for go mobile, it looks like you need to cast the null value to the type.
From the SeqTest.java file:
public void testNilErr() throws Exception {
Testpkg.Err(null); // returns nil, no exception
}
Edit: A non-exception example, too:
byte[] got = Testpkg.BytesAppend(null, null);
assertEquals("Bytes(null+null) should match", (byte[])null, got);
got = Testpkg.BytesAppend(new byte[0], new byte[0]);
assertEquals("Bytes(empty+empty) should match", (byte[])null, got);
It may be as simple as:
GoLibrary.GoStruct goStruct = GoLibrary.ExportedGoFunction();
if (goStruct != (GoLibrary.GoStruct)null) {
// This block should not be executed, but it is
Log.d("GoLog", "goStruct is not null");
}
EDIT: Suggestion for utility method:
You could add a utility function to the library to give you the typed nil
value.
func NullVal() *GoStruct {
return nil
}
Still a bit hacky, but it should be less overhead than multiple wrappers and exception handling.