3

We are using SWIG to create the JNI API between C++ API to Java in Android.

So for example lets say that our C++ class is:

class TestAnnotation {

public:
    void setMessage(char * message);
    char * getMessage();

private:
    char* message = nullptr;
};

SWIG produces this auto generated Java class:

public class TestAnnotation {
  ...

  public void setMessage(String message) {
    myJNI.TestAnnotation_setMessage(swigCPtr, this, message);
  }

  public String getMessage() {
    return myJNI.TestAnnotation_getMessage(swigCPtr, this);
  }
}

As you can see, message can be null and it is possible for the get & set methods to receive/return a null String (the JNI auto generated code behaves as expected in this case and allows to either use jstring or null).

My question is whether: SWIG is capable of adding annotations like @Nullable or @NonNull to match the C++ API (if we need to supply "hints" to SWIG, that would also work).

So in this case the desired auto generated Java API will be:

public class TestAnnotation {
  ...

  public void setMessage(@Nullable String message) {
    myJNI.TestAnnotation_setMessage(swigCPtr, this, message);
  }

  @Nullable
  public String getMessage() {
    return myJNI.TestAnnotation_getMessage(swigCPtr, this);
  }
}

This is important as we are using this Java API with Kotlin and the absence of the annotations make it harder to use the Kotlin smart features.

Doron Yakovlev Golani
  • 5,188
  • 9
  • 36
  • 60

1 Answers1

2

Give your example C++ class in a file called test.h you can generate a Java wrapper with the annotations you wanted using this syntax:

%module test

%javamethodmodifiers TestAnnotation::getMessage() %{
  @Nullable
  public%};

%typemap(jstype) char *message "@Nullable String";

%include "test.h"

It's a little counter intuitive given the naming focuses on other uses cases, but totally sensible usage nonetheless.

You can of course make the typemap for the inputs less specific by not naming the parameter in it (e.g. %typame(jstype) char * "...").

And you'll want to use another typemap to set up the imports:

%typemap(javaimports) TestAnnotation %{
import android.support.annotation;
%}

Which can be made more generic with:

%typemap(javaimports) SWIGTYPE %{
import android.support.annotation;
%}
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • This solution works, but it has two drawbacks: 1) It is very specific, I will have to add a `%typemap` with `@Nullable` for every type I am using (and if I want to add `@NonNull` it will be an even bigger pain). 2) The code is not compiling as the import for `android.support.annotation` is missing. – Doron Yakovlev Golani Apr 26 '19 at 18:27