{"id":381970,"date":"2024-06-29T03:59:33","date_gmt":"2024-06-29T03:59:33","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=381970"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=381970","title":{"rendered":"<span>Android interop with SWIG (a guide). From simple to weird. Part 2 \u2014 weird<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><em>This is Part 2. Part 1 is\u00a0<\/em><a href=\"https:\/\/habr.com\/ru\/post\/536314\/\" rel=\"noopener noreferrer nofollow\"><em>here<\/em><\/a><em>.<\/em><\/p>\n<p><em>Part 2<\/em>\u00a0covers the use of typemaps, complex &amp; weird cases, and debugging suggestions. This part requires an understanding of Part 1 &#8212; usage of\u00a0<a href=\"http:\/\/swig.org\/\" rel=\"noopener noreferrer nofollow\">SWIG<\/a>\u00a0in simple cases.<\/p>\n<p>This is a practical guide, with <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\" rel=\"noopener noreferrer nofollow\">Android Studio project<\/a> you can play with.<\/p>\n<h3>Table of contents<\/h3>\n<ul>\n<li>\n<p><a href=\"#complex_cases\" rel=\"noopener noreferrer nofollow\">Complex cases<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#ptr_to_string\" rel=\"noopener noreferrer nofollow\">Shared pointer to std::string (C++ side typemaps)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#java_date_time_t\" rel=\"noopener noreferrer nofollow\">Java Date and C++ time_t (Java-side typemaps)<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#more_complexity\" rel=\"noopener noreferrer nofollow\">More complexity (all the weirdness)<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#byte_array_2d\" rel=\"noopener noreferrer nofollow\">Shared pointer to vector of shared pointers to vectors of bytes<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#std_function\" rel=\"noopener noreferrer nofollow\">std::function<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#gc_ref_counting\" rel=\"noopener noreferrer nofollow\">GC and Reference counting (or how to break the code)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#debug_swig\" rel=\"noopener noreferrer nofollow\">Debugging SWIG<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#debug_swig_script\" rel=\"noopener noreferrer nofollow\">Debugging SWIG script<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#debug_generated_code\" rel=\"noopener noreferrer nofollow\">Debugging generated code and runtime errors<\/a> <\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#misc\" rel=\"noopener noreferrer nofollow\">Misc<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#resources\" rel=\"noopener noreferrer nofollow\">Resources<\/a><\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"complex_cases\" id=\"complex_cases\"><\/a><\/p>\n<h2>Complex cases<\/h2>\n<p>This section covers the typemaps. <\/p>\n<p><a class=\"anchor\" name=\"ptr_to_string\" id=\"ptr_to_string\"><\/a><\/p>\n<h3>Shared pointer to std::string (C++ side typemaps)<\/h3>\n<p>Scheme<\/p>\n<pre><code class=\"cpp\">%shared_ptr(std::string);<\/code><\/pre>\n<p>just doesn&#8217;t seem to be working \u00af\\_(\u30c4)_\/\u00af &#8212; the generated code will not compile. Because SWIG, when generating a wrapper for <code>shared_ptr<\/code> arguments, expects that they are SWIG-wrapped types and relies on SWIG-generated functions, which are not part of the <code>java.lang.String<\/code> class that we expect to use on the Java side. We have to create our own typemap to allow <code>std::shared_ptr&lt;std::string><\/code>. Typemap instructs SWIG on how to process a particular type. I will not dig into deep details, see <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps\" rel=\"noopener noreferrer nofollow\">Java typemaps chapter<\/a>, especially <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps_c_to_java_types\" rel=\"noopener noreferrer nofollow\">C++ typemaps<\/a> and <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps_c_to_java_types\" rel=\"noopener noreferrer nofollow\">Director-specific typemaps<\/a> within the chapter.<\/p>\n<p><a class=\"anchor\" name=\"table_1\" id=\"table_1\"><\/a><\/p>\n<p>Look to the following table for a simpler understanding of the typemaps (description is below the table).<\/p>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th data-colwidth=\"50\" width=\"50\">\n<\/th>\n<th data-colwidth=\"128\" width=\"128\">\n<p>Type in level<\/p>\n<\/th>\n<th data-colwidth=\"92\" width=\"92\">\n<p>Type 1<\/p>\n<\/th>\n<th data-colwidth=\"80\" width=\"80\">\n<p>Type 2<\/p>\n<\/th>\n<th data-colwidth=\"90\" width=\"90\">\n<p>Type 3<\/p>\n<\/th>\n<th>\n<p>Typemaps between levels<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>1<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>Java<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>String<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>Date<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>byte[][]<\/p>\n<\/td>\n<td>\n<p>%typemap(jstype)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>%typemap(javain\u2193|javaout\u2191|javadirectorin\u2191|javadirectorout\u2193]<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>2<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>Java intermediary<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>String<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>long<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>byte[][]<\/p>\n<\/td>\n<td>\n<p>%typemap(jtype)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>Automatically done by JNI (no typemap)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>3<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>JNI (C++ intermediary)<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>jstring<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>jlong<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>jobjectArray<\/p>\n<\/td>\n<td>\n<p>%typemap(jni)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>%typemap(in\u2193|out\u2191|directorin\u2191|directorout\u2193)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>4<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>C++<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>std::shared_ptr&lt;std::string><\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>time_t (equals) long long<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>shared_<em>ptr&lt;vector&lt;shared_<\/em>ptr&lt;vector&lt;byte>>>><\/p>\n<\/td>\n<td>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>To pass anything between C++ and JAVA, back or forth, you need to go through the four levels. Levels 1 and 4 are Java and C++ &#8212; the levels you are writing business logic at. To go from 1 to 4 or back you have to pass 3 levels of conversion. 2->3 and back is done by JNI. But 1->2 and 3->4 and back are done by the typemaps. Some typemaps are defining types to operate on, in the table, they are residing on the lines with numbers (levels). Some typemaps are defining level and direction, at which they will convert type (between lines with numbers); arrow explains in which direction the particular typemap is working. Note that regular and director typemaps directions are flipped, i.e. <code>%typemap(in)<\/code> doing the same operation as <code>%typemap(directorout)<\/code>. For example, <code>%typemap(in) std::shared_ptr&lt;std::string><\/code> is converting level 3->4; level 4 C++ type is defined in this typemap; level 3 JNI type <code>jstring<\/code> is defined by another typemap: <code>%typemap(jni) std::shared_ptr&lt;std::string> \"jstring\"<\/code>. The table also covered the <code>Date<\/code> and <code>byte[][]<\/code> type, we will talk about them in the later chapters.<\/p>\n<p>It might sound complicated, but you will eventually get how everything is working while practicing. Read the comments in the following snippet, they are explaining everything in place.  So, to proceed, crate new file <code>swig\/std_shared_ptr_to_string.i<\/code> and fill it with content.<\/p>\n<pre><code class=\"cpp\">%include &lt;std_shared_ptr.i> %include &lt;std_string.i>  %{ #include &lt;memory> #include &lt;string> %}  namespace std {     \/\/ To properly recognize type defined in our Types.h     %template(shared_ptr_to_string) std::shared_ptr&lt;std::string>; }  %{ namespace {     std::shared_ptr&lt;std::string> convertStringFromJavaToCpp(JNIEnv *jenv, jstring javaString)     {         const char * psz_string = jenv->GetStringUTFChars(javaString, NULL);         if (!psz_string)         {             return nullptr;         }          std::shared_ptr&lt;std::string> cppString = std::make_shared&lt;std::string>(psz_string);         jenv->ReleaseStringUTFChars(javaString, psz_string);         return cppString;     }      jstring convertStringFromCppToJava(JNIEnv *jenv, std::shared_ptr&lt;std::string> cppString)     {         if (!cppString)         {             return nullptr;         }          return jenv->NewStringUTF(cppString->c_str());     } } %}  \/\/ \/\/ Type definitions for C type 'std::shared_ptr&lt;std::string>' \/\/  %typemap(jstype) std::shared_ptr&lt;std::string> \"java.lang.String\" \/\/ Java type %typemap(jtype) std::shared_ptr&lt;std::string> \"java.lang.String\" \/\/ Java intermediary type %typemap(jni) std::shared_ptr&lt;std::string> \"jstring\" \/\/ JNI C type (or intermediary C type)  \/\/ \/\/ Java-side typemaps \/\/  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) %typemap(javain) std::shared_ptr&lt;std::string> \"$javainput\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) %typemap(javaout) std::shared_ptr&lt;std::string> {      return $jnicall; }  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) for director methods %typemap(javadirectorout) std::shared_ptr&lt;std::string> \"$javacall\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) for director methods %typemap(javadirectorin) std::shared_ptr&lt;std::string> \"$jniinput\"  \/\/ \/\/ C++ side typemaps \/\/  \/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(in) std::shared_ptr&lt;std::string> {     $1 = convertStringFromJavaToCpp(jenv, $input); }  \/\/ Conversion from C++ type to 'jni' (JNI C type) %typemap(out) std::shared_ptr&lt;std::string> {     return convertStringFromCppToJava(jenv, $1); }  \/\/ Conversion from 'jni' (JNI C type) to C++ type for director methods %typemap(directorout) std::shared_ptr&lt;std::string> {     $result = convertStringFromJavaToCpp(jenv, $input); }  \/\/ Conversion from C++ type to 'jni' (JNI C type) for director methods \/\/ Note: Ljava\/lang\/String; is the JNI field descriptor for the Java String type %typemap(directorin,descriptor=\"Ljava\/lang\/String;\") std::shared_ptr&lt;std::string> {     $input = convertStringFromCppToJava(jenv, $1); }<\/code><\/pre>\n<p>Include this file into your SWIG interface file:<\/p>\n<pre><code class=\"cpp\">%module(directors=\"1\") SwigAndroidGuide  %include &lt;std_shared_ptr.i> %include &lt;std_string.i> %include \"std_shared_ptr_to_string.i\" \/\/ &lt;&lt; Add this line<\/code><\/pre>\n<p>Re-run SWIG script <code>run_swig.sh<\/code> and you will be able to run your application.<\/p>\n<p>Note that I&#8217;ve created separate conversion functions, which are used in the typemaps. This allows:<\/p>\n<ul>\n<li>\n<p>Writing clear C++ code; note, you have to use <code>$input<\/code> and similar constructions in typemap body;<\/p>\n<\/li>\n<li>\n<p>You know what exactly C++ function is doing by giving it a proper name;<\/p>\n<\/li>\n<li>\n<p>Typemaps are looking clearer (and you know what they are doing by reading C++ function names);<\/p>\n<\/li>\n<li>\n<p>Re-use these functions, as regular and director typemaps are the same in most of the cases;<\/p>\n<\/li>\n<li>\n<p>Decrease in code size. Each time you use the argument particular typemap is working with, the typemap code will be copy-pasted into the SWIG-generated file. This increases code size, which is not great for mobile devices.<\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"java_date_time_t\" id=\"java_date_time_t\"><\/a><\/p>\n<h3>Java Date and C++ time_t (Java-side typemaps)<\/h3>\n<p>For <code>java.util.Date<\/code> it is much simpler to write such typemaps on the Java side, to avoid unnecessary JNI calls in C++. See <a href=\"#table_1\" rel=\"noopener noreferrer nofollow\">Table 1<\/a> to see how we map Date type to C++. In C++ it will be the <code>time_t<\/code>, which is <code>long long<\/code>.<\/p>\n<p>Let&#8217;s add the creation date to our message, in <code>Message.h<\/code>:<\/p>\n<pre><code class=\"cpp\">class Message { public:     \/\/ Add these lines     time_t getCreationDate() const { return _creationDate; }     void setCreationDate(time_t creationDate) { _creationDate = creationDate; } private:      time_t _creationDate; \/\/ &lt; Add this line<\/code><\/pre>\n<p>If you run SWIG script <code>run_swig.sh<\/code> now, you will notice the new file:<\/p>\n<pre><code>\/app\/src\/main\/java\/com\/goldberg\/swigandroidguide\/swiggenerated\/SWIGTYPE_p_time_t.java<\/code><\/pre>\n<p>and new functions in WSIG-generated <code>Message.java<\/code>:<\/p>\n<pre><code class=\"java\">public SWIGTYPE_p_time_t getCreationDate() {   return new SWIGTYPE_p_time_t(SwigAndroidGuideJNI.Message_getCreationDate(swigCPtr, this), true); }  public void setCreationDate(SWIGTYPE_p_time_t creationDate) {   SwigAndroidGuideJNI.Message_setCreationDate(swigCPtr, this, SWIGTYPE_p_time_t.getCPtr(creationDate)); }<\/code><\/pre>\n<p>This means, as you guess, that the type <code>time_t<\/code> can&#8217;t be handled properly.<\/p>\n<p>Let&#8217;s add new SWIG file <code>swig\/time_t.i<\/code>. We do only assignments for the C++ portion of the typemaps. But java typemaps are including the actual Java code. Note, I didn&#8217;t create separate function as I did in C++, because code is very simple. One more reason &#8212; one Java file is generated for each SWIG-wrapped class, so it is just harder to do than in C++, where everything is in one large *.cpp file.<\/p>\n<pre><code class=\"cpp\">\/\/ \/\/ Type definitions for C type 'time_t' \/\/  %typemap(jstype) time_t \"java.util.Date\" \/\/ Java type %typemap(jtype) time_t \"long\" \/\/ Java intermediary type %typemap(jni) time_t \"jlong\" \/\/ JNI C type (or intermediary C type)  \/\/ \/\/ Java-side typemaps \/\/  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) %typemap(javain) time_t \"$javainput.getTime() \/ 1000\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) %typemap(javaout) time_t {     return new java.util.Date($jnicall * 1000); }  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) for director methods %typemap(javadirectorin) time_t \"new java.util.Date($jniinput * 1000)\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) for director methods %typemap(javadirectorout) time_t \"$javacall.getTime() \/ 1000\"  \/\/ \/\/ C++ side typemaps \/\/ All the typemaps are just an assignments. \/\/  %typemap(in) time_t \"$1 = $input;\" \/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(out) time_t \"$result = $1;\" \/\/ Conversion from C++ type to 'jni' (JNI C type)  \/\/ Conversion from 'jni' (JNI C type) to C++ type for director methods %typemap(directorout) time_t \"$result = $input;\"  \/\/ Conversion from C++ type to 'jni' (JNI C type) for director methods \/\/ Note: Ljava\/lang\/String; is the JNI field descriptor for the Java String type %typemap(directorin, descriptor = \"Ljava\/util\/Date;\") time_t \"$input = $1;\"<\/code><\/pre>\n<p>Include this file into SWIG instructions file <code>SwigAndroidGuide.i<\/code>:<\/p>\n<pre><code class=\"cpp\">%module(directors=\"1\") SwigAndroidGuide  \/\/ ...  %include &lt;std_shared_ptr.i> %include &lt;std_string.i> \/\/ ... %include \"time_t.i\" \/\/ &lt;&lt; Add this line<\/code><\/pre>\n<p>Now run SWIG script <code>run_swig.sh<\/code> and see that <code>Message.java<\/code> has a proper implementation of our new functions.<\/p>\n<pre><code class=\"java\">public java.util.Date getCreationDate() {     return new java.util.Date(SwigAndroidGuideJNI.Message_getCreationDate(swigCPtr, this) * 1000); }  public void setCreationDate(java.util.Date creationDate) {     SwigAndroidGuideJNI.Message_setCreationDate(swigCPtr, this, creationDate.getTime() \/ 1000); }<\/code><\/pre>\n<p>Here the <code>javain\/out<\/code> typemaps were unfolded:<\/p>\n<ul>\n<li>\n<p><code>$javainput<\/code> => <code>creationDate<\/code> argument in <code>setCreationDate(java.util.Date creationDate)<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>$jnicall<\/code> => <code>SwigAndroidGuideJNI.Message_getCreationDate(swigCPtr, this)<\/code> in <code>getCreationDate()<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>Let&#8217;s write some code to use our new functions.<\/p>\n<p><strong>ActivityModel.cpp:<\/strong><\/p>\n<pre><code class=\"cpp\">    void ActivityModel::onCreate(IAndroidActivity *androidActivity)     {         \/\/ ...         message->setText(make_shared&lt;string>(\"Greetings!\"));          \/\/ Add these lines          time_t now = time(nullptr);         __android_log_print(ANDROID_LOG_DEBUG, TAG, \"%s\", asctime(localtime(&amp;now)));         message->setCreationDate(now);          \/\/ ...<\/code><\/pre>\n<p><strong>MainActivity.java<\/strong> (git dif):<\/p>\n<pre><code class=\"diff\">- Log.d(TAG, String.format(Locale.US, \"Message sent: '%d %s'\", message.getId(), message.getText())); + Log.d(TAG, String.format(Locale.US, \"Message sent: '%d %s %s'\", message.getId(), message.getText(), message.getCreationDate()));<\/code><\/pre>\n<p>Run the application and verify that log output is correct &#8212; the same date and time are printed in C++ and Java:<\/p>\n<pre><code>D\/ActivityModel: Thu Oct 29 18:46:08 2020 D\/MainActivity: Message sent: '22 Greetings! Thu Oct 29 18:46:08 GMT+02:00 2020'<\/code><\/pre>\n<p><a class=\"anchor\" name=\"more_complexity\" id=\"more_complexity\"><\/a><\/p>\n<h2>More complexity (all the weirdness)<\/h2>\n<p><a class=\"anchor\" name=\"byte_array_2d\" id=\"byte_array_2d\"><\/a><\/p>\n<h3>Shared pointer to vector of shared pointers to vectors of bytes<\/h3>\n<p><code>shared_ptr&lt;vector&lt;shared_ptr&lt;vector&lt;unsigned char>>>><\/code><\/p>\n<p>At first, wrapping std containers with SWIG is easy. Just include this into your SWIG file:<\/p>\n<pre><code class=\"cpp\">%include &lt;std_vector.i> \/\/ Or another C++ container %template(Std_Vector_Int) std::vector&lt;int>; \/\/ Define a template and set a name for your type %template(Std_Vector_Message) std::vector&lt;message>; \/\/ Define a template and set a name for your type<\/code><\/pre>\n<p>Run SWIG, and you will get the working code:<\/p>\n<pre><code class=\"java\">public class Std_Vector_Int extends java.util.AbstractList&lt;Integer> implements java.util.RandomAccess {   \/\/ ...    public Integer get(int index) {     return doGet(index);   }    public Integer set(int index, Integer e) {     return doSet(index, e);   }    public boolean add(Integer e) {     modCount++;     doAdd(e);     return true;   }    public Integer remove(int index) {     modCount++;     return doRemove(index);   }    public int size() {     return doSize();   }    public Std_Vector_Int() {     this(SwigAndroidGuideJNI.new_Std_Vector_Int__SWIG_0(), true);   }    \/\/ ... }<\/code><\/pre>\n<p>If you&#8217;ll write C++ code like this:<\/p>\n<pre><code class=\"cpp\">public int decryptMessages(std::vector&lt;message> messages) {     return \/\/ ... }<\/code><\/pre>\n<p>Generated Java method to call this C++ method will be like:<\/p>\n<pre><code class=\"cpp\">public int decryptMessages(Std_Vector_Message messages) {     \/\/ ... }<\/code><\/pre>\n<p>The same applies to <code>%template(Std_Vector_Int) std::vector&lt;int><\/code>. Quite simple. However, the downsides of this:<\/p>\n<ol>\n<li>\n<p>Non-native Java containers. The generated types are just simple wrappers for real C++ objects.<\/p>\n<\/li>\n<li>\n<p>Per-element access, i.e. each access to element is C++ call &#8212; lower performance.<\/p>\n<\/li>\n<li>\n<p>Need to explicitly define a SWIG template for each use-case.<\/p>\n<\/li>\n<\/ol>\n<p><strong>Despite the downsides, I think the above should be the default way<\/strong>. Unless you have special requirements, i.e. for performance-critical tasks. To overcome the first problem, you can create converter functions, that will convert this to Java containers. This is easy. Well, issue #2 is not an issue for most cases, but it was an issue in our case. We wanted to pass byte arrays between Java and C++ without the performance penalty. Java has a <code>ByteBuffer<\/code> type, which storage can be allocated in C++ heap (called <code>direct ByteBuffer<\/code>); but there are numerous problems with the <code>ByteBuffer<\/code> type associated with the inability to manage its memory. Also, we wanted Java to interact with our existing code without actually changing it or having any additional <em>conversion layer<\/em>. Using the approach given below data is still copied between C++ and Java (opposite to what <code>direct ByteBuffer<\/code> offers), but the data access and memory management are efficient, and we don&#8217;t experience any problems.<\/p>\n<h4>So, shared pointer to vector of shared pointers to vectors of bytes<\/h4>\n<p><code>shared_ptr&lt;vector&lt;shared_ptr&lt;vector&lt;unsigned char>>>><\/code> Well, you can think of <em>this is too much<\/em>. But this is just an equivalent of Java <code>byte[][]<\/code>. C++ syntax is unfriendly. In the application I&#8217;ve worked on, this type was holding parts of encrypted data. We don&#8217;t want this (huge amounts of data) to be copied when passing around, and we wanted quick access from Java. Before proceeding, see our <code>Types.h<\/code>, types from it are used in C++ and SWIG:<\/p>\n<pre><code class=\"cpp\">#include &lt;memory> #include &lt;vector>  typedef unsigned char byte; typedef std::shared_ptr &lt;std::string> shared_ptr_to_string; typedef std::shared_ptr&lt;std::vector&lt;std::shared_ptr&lt;std::vector&lt;byte>>>> shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes;<\/code><\/pre>\n<p>Let&#8217;s write our C++ code first.<\/p>\n<pre><code class=\"cpp\">class ActivityModel { public:     \/\/ ...      \/\/ Add this function     int decryptMessages(shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes messages); };<\/code><\/pre>\n<p>As usual, the implementation doesn&#8217;t do anything real. We are covering only cross-language interaction here.<\/p>\n<pre><code class=\"cpp\">int ActivityModel::decryptMessages(shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes messages) {     int bytesDecrypted = 0;     for (int i = 0; i &lt; messages->size(); ++i)     {         bytesDecrypted += messages->at(i)->size();     }      return bytesDecrypted; }<\/code><\/pre>\n<p>SWIG code is given below. Place it in <code>std_shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes.i<\/code>. The code is well-commented and self-explanatory. Read it carefully if you want to dig into it. The approach used is the same as for <a href=\"#ptr_to_string\" rel=\"noopener noreferrer nofollow\">shared_ptr&lt;string><\/a>. See the conversion map in the <a href=\"#table_1\" rel=\"noopener noreferrer nofollow\">Table 1<\/a>.<\/p>\n<pre><code class=\"cpp\">%include &lt;std_shared_ptr.i> %include &lt;std_vector.i>  namespace std {    \/\/ To properly recognize type defined in our Types.h    %template(shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes) std::shared_ptr&lt;std::vector&lt;std::shared_ptr&lt;std::vector&lt;unsigned char=\"\">>>>; }  \/\/ Use as Swig type alias %define %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes std::shared_ptr&lt;std::vector&lt;std::shared_ptr&lt;std::vector&lt;unsigned char=\"\">>>> %enddef  %{ #include \"Types.h\"  namespace {     \/*      * C++ type 'std::shared_ptr&lt;std::vector&lt;std::shared_ptr&lt;std::vector&lt;unsigned char=\"\">>>>' with alias 'shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes'      * is equivalent to Java type 'byte[][]',      * which is equivalent to JNI type: 'jobjectArray' with 'jbyteArray' elements.      * JNI descriptors are 'jobjectArray' = '[[B' (treat as byte[][]), 'jbyteArray' = '[B'.      * Note: more logical will be to pass two-dimensional array, but JNI does support only 1-dimentional arrays.      *\/      shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes convertArrayOfArraysOfByteFromJavaToCpp(JNIEnv *jenv, jobjectArray javaArrayOfArraysOfBytes)     {         if(javaArrayOfArraysOfBytes == nullptr) return nullptr;          \/\/ Create outer vector          jsize sizeOfArrayOfArrays = jenv->GetArrayLength(javaArrayOfArraysOfBytes);         std::shared_ptr&lt;std::vector&lt;shared_ptr_to_vector_of_bytes>> vectorOfVectorsOfBytes = std::make_shared&lt;std::vector&lt;shared_ptr_to_vector_of_bytes>>();         vectorOfVectorsOfBytes->reserve((size_t) sizeOfArrayOfArrays);          \/\/ Push all inner vectors into outer vector          for(jsize i = 0; i &lt; sizeOfArrayOfArrays; ++i)         {             \/\/ Null array              jbyteArray arrayOfBytes = (jbyteArray) (jenv->GetObjectArrayElement(javaArrayOfArraysOfBytes, i));             if (arrayOfBytes == nullptr)             {                 vectorOfVectorsOfBytes->push_back(nullptr);                 continue;             }              \/\/ Empty array              jsize sizeOfBuffer = jenv->GetArrayLength(arrayOfBytes);             if(sizeOfBuffer == 0)             {                 vectorOfVectorsOfBytes->push_back(std::make_shared&lt;vector_of_bytes>());                 continue;             }              \/\/ Array with elements              jbyte *bufferOfBytes = jenv->GetByteArrayElements(arrayOfBytes, nullptr);             shared_ptr_to_vector_of_bytes vector = std::make_shared&lt;vector_of_bytes>(bufferOfBytes, bufferOfBytes + sizeOfBuffer);             vectorOfVectorsOfBytes->push_back(vector);             jenv->ReleaseByteArrayElements(arrayOfBytes, bufferOfBytes, 0);         }          return vectorOfVectorsOfBytes;     }      jobjectArray convertArrayOfArraysOfByteFromCppToJava(JNIEnv *jenv, shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes vectorOfVectorsOfBytes)     {         if (!vectorOfVectorsOfBytes) return nullptr;          \/\/ Allocate array of objects, where each object is 'jbyteArray'          jsize sizeOfArrayOfArrays = (jsize) vectorOfVectorsOfBytes->size();         jclass classOfJByteArray = jenv->FindClass(\"[B\"); \/\/ '[B' is the JNI field descriptor for the Java byte[] type         jobjectArray arrayOfArraysOfBytes = jenv->NewObjectArray(sizeOfArrayOfArrays, classOfJByteArray, nullptr);          \/\/ Set inner arrays to it          for(jsize i = 0; i &lt; sizeOfArrayOfArrays; ++i)         {             \/\/ Null array              shared_ptr_to_vector_of_bytes vectorOfBytes = vectorOfVectorsOfBytes->at(i);             if (!vectorOfBytes)             {                 continue;             }              \/\/ Empty array              jsize sizeOfArray = (jsize) vectorOfBytes->size();             jbyteArray javaArrayOfBytes = jenv->NewByteArray(sizeOfArray);             jenv->SetObjectArrayElement(arrayOfArraysOfBytes, (jsize) i, javaArrayOfBytes);             if (sizeOfArray == 0)             {                 continue;             }              \/\/ Array with elements              jenv->SetByteArrayRegion(javaArrayOfBytes, 0, sizeOfArray, (jbyte *) &amp;amp;(vectorOfBytes->at(0)));         }          return arrayOfArraysOfBytes;     } } %}  %typemap(jstype) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"byte[][]\" %typemap(jtype) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"byte[][]\" %typemap(javain) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"$javainput\" %typemap(jni) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"jobjectArray\" %typemap(in) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes {     $1 = convertArrayOfArraysOfByteFromJavaToCpp(jenv, $input); } %typemap(javadirectorout) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"$javacall\" %typemap(directorout) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes {     $result = convertArrayOfArraysOfByteFromJavaToCpp(jenv, $input); } %typemap(argout) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes;  \/\/ Just override the default and do nothing %typemap(freearg) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes; \/\/ Just override the default and do nothing %typemap(javaout) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes {      return $jnicall; } %typemap(out) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes {     $result = convertArrayOfArraysOfByteFromCppToJava(jenv, $1); } %typemap(javadirectorin) %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes \"$jniinput\" \/\/ '[[B' is the JNI field descriptor for the Java 'byte[][]' type %typemap(directorin,descriptor=\"[[B\") %shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes {         $input = convertArrayOfArraysOfByteFromCppToJava(jenv, $1); }<\/code><\/pre>\n<p>Include this into the main SWIG file <code>SwigAndroidGuide.i<\/code>.<\/p>\n<pre><code class=\"cpp\">\/\/ ... %include &lt;std_string.i> %include \"std_shared_ptr_to_string.i\" %include \"std_shared_ptr_to_vector_of_shared_ptr_to_vector_of_bytes.i\" \/\/ Add this line  %{ #include \"Types.h\" \/\/ Add this line #include \"ActivityModel.h\" \/\/ ... %}  \/\/ Add this line. \/\/ Important! This should be included before any usage of types typedefed inside. \/\/ Otherwise SWIG can't process them properly. %include \"Types.h\"  %include \"ActivityModel.h\" \/\/ ...<\/code><\/pre>\n<p>Generate SWIG wrappers running <code>run_swig.sh<\/code>. Generated Java function in <code>ActivityModel.java<\/code> looks like this &#8212; with real Java type <code>byte[][]<\/code>.<\/p>\n<pre><code class=\"java\">public int decryptMessages(byte[][] messages) {     return SwigAndroidGuideJNI.ActivityModel_decryptMessages(swigCPtr, this, messages); }<\/code><\/pre>\n<p>Usage in <code>MainActivity.java<\/code>:<\/p>\n<pre><code class=\"java\">public class MainActivity extends AppCompatActivity {     \/\/ ...     @Override     protected void onCreate(Bundle savedInstanceState)     {         \/\/ ...         decrypt();     }     \/\/ ...     private void decrypt()     {         byte[][] messages = new byte[5][];         for (int i = 0; i &lt; messages.length; ++i)         {             messages[i] = new byte[(i + 1) * 385];         }          int result = activityModel.decryptMessages(messages);         Log.d(TAG, \"decrypt() Message bytes decrypted: \" + result);     }<\/code><\/pre>\n<p>And the result is as expected, so it was called correctly: <code>D\/MainActivity: decrypt() Message bytes decrypted: 5775<\/code><\/p>\n<p><strong>P.S.<\/strong> The easier case of <code>shared_ptr&lt;vector&lt;byte>><\/code> is not covered in this article, but you can find the typemap in the file <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\/blob\/master\/swig\/std_shared_ptr_to_vector_of_bytes.i\" rel=\"noopener noreferrer nofollow\">\/swig\/std_shared_ptr_to_vector_of_bytes.i<\/a><\/p>\n<p><a class=\"anchor\" name=\"std_function\" id=\"std_function\"><\/a><\/p>\n<h3>std::function<\/h3>\n<p>Or passing functions to Java. The simple approach here is to create a class similar to Java <code>Runnable<\/code><\/p>\n<pre><code class=\"java\">class Runnable { public:     virtual void run() = 0; };<\/code><\/pre>\n<p>Subclass it where needed and be fine. But we wanted to make the experience more &#8216;integrated&#8217;. Especially regarding cool feature of <code>std::function<\/code> &#8212; capturing variables. The class we are going to create now will allow us to run our <code>std::function<\/code> from C++ in Java. We don&#8217;t want to use POSIX threads, as a lot of effort required to do so, instead of using native Android\/iOS background task management. Let&#8217;s start creating a C++ interface to be subclassed in Java &#8212; <code>ITaskScheduler.h<\/code><\/p>\n<pre><code class=\"cpp\">class ITaskScheduler { public:     virtual ~ITaskScheduler() = default;     virtual bool isMainThread() = 0;     virtual void executeOnBackgroundThread(std::function&lt;void()> function) = 0;     virtual void executeOnUIThread(std::function&lt;void()> function) = 0; };<\/code><\/pre>\n<p>After including this file for processing into the SWIG file <code>SwigAndroidGuide.i<\/code> as usual, and running SWIG notice in <code>git status<\/code> that SWIG can&#8217;t process <code>std::function<\/code> properly, generating mock file:<\/p>\n<pre><code>app\/src\/main\/java\/com\/goldberg\/swigandroidguide\/swiggenerated\/SWIGTYPE_p_std__functionT_void_fF_t.java<\/code><\/pre>\n<p>We have to write a special typemap for this case. I didn&#8217;t write it. It is taken from <a href=\"https:\/\/stackoverflow.com\/a\/32668302\/5035991\" rel=\"noopener noreferrer nofollow\">Stackoverflow<\/a>, written by the great author Flexo, who knows how to deal with SWIG. If I don&#8217;t found this answer, we&#8217;d stick with the <code>Runnable<\/code> approach mentioned above, as it is much simpler. I will not insert code here, it&#8217;s quite complex and large. See the code directly in <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\/blob\/master\/swig\/std_function.i\" rel=\"noopener noreferrer nofollow\">file<\/a> <code>\/swig\/std_function.i<\/code> from the <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\" rel=\"noopener noreferrer nofollow\">repository<\/a> and read the original <a href=\"https:\/\/stackoverflow.com\/a\/32668302\/5035991\" rel=\"noopener noreferrer nofollow\">answer<\/a>. In this file, there are two definitions for <code>std::function<\/code><\/p>\n<pre><code class=\"cpp\">\/\/ Ret = Return type %define %std_function(Name, Ret, ...) %define %std_function_void(Name, Ret)<\/code><\/pre>\n<p>I have to add <code>%std_function_void<\/code>, which implementation is 97% matches the <code>%std_function<\/code> because for some reason <code>%define<\/code> statement was not unfolding properly when no variadic arguments were passed <code>...<\/code>. When you pass no variadic arguments, the script thinks that <strong>one<\/strong> empty argument is passed, while it <strong>should<\/strong> think <strong>zero<\/strong> arguments passed. <code>%std_function_void<\/code> eliminates variadic argument. I don&#8217;t know what&#8217;s the reason, maybe it is due to OS type\/version or SWIG version.<\/p>\n<p>So this code in the SWIG file <code>SwigAndroidGuide.i<\/code>:<\/p>\n<pre><code class=\"cpp\">%std_function(FunctorVoid, void);<\/code><\/pre>\n<p>was giving the error when running SWIG: <code>SwigAndroidGuide.i:13: Error: Syntax error in: $typemap(jstype,)<\/code><\/p>\n<p>Ok, let&#8217;s use it. The usage is simple. Just define in your main SWIG file <code>SwigAndroidGuide.i<\/code> which functions you want to pass through the language boundaries. The only downside of this approach in comparison to <code>Runnable<\/code>, is that we have to define each type used.<\/p>\n<pre><code class=\"cpp\">%include \"std_function.i\"  \/\/ ...  \/\/ Name is FunctorVoid; void return type and void arguments. %std_function_void(FunctorVoid, void);  \/\/ Name is FunctorVoidMessage; void return type and shared_ptr&lt;message> argument. %std_function(FunctorVoidMessage, void, std::shared_ptr&lt;swigandroidguide::message>);<\/code><\/pre>\n<p> When re-generating SWIG (<code>run_swig.sh<\/code>), your curious type file <code>SWIGTYPE_p_std__functionT_void_fF_t.java<\/code> transforms to <code>app\/src\/main\/java\/com\/goldberg\/swigandroidguide\/swiggenerated\/SWIGTYPE_p_f___void.java<\/code><\/p>\n<p>Probably the file name is assembled in the included script <code>std_function.i<\/code>, but I can&#8217;t understand where \ud83d\ude42 Let&#8217;s implement our class in Java:<\/p>\n<pre><code class=\"java\">final class TaskScheduler extends ITaskScheduler {     private static final Handler mainThreadHandler = new Handler();     private static final ExecutorService backgroundTaskExecutor = Executors.newSingleThreadExecutor();      @Override     public boolean isMainThread()     {         return Looper.getMainLooper().getThread() == Thread.currentThread();     }     @Override     public void executeOnBackgroundThread(FunctorVoid function)     {         backgroundTaskExecutor.execute(function::call);     }      @Override     public void executeOnUIThread(FunctorVoid function)     {         mainThreadHandler.post(function::call);     } } <\/code><\/pre>\n<p>To use function references, add this to your app-level <code>app\/build.gradle<\/code>:<\/p>\n<pre><code class=\"dart\">android {     \/\/ ...     compileOptions {         sourceCompatibility JavaVersion.VERSION_1_8         targetCompatibility JavaVersion.VERSION_1_8     }<\/code><\/pre>\n<p>Let&#8217;s also add functions to <code>IAndroidActivity<\/code> to allow us to use our newly created class:<\/p>\n<pre><code class=\"cpp\">class IAndroidActivity { public:     virtual ITaskScheduler * getTaskScheduler() = 0;     \/\/ ... };<\/code><\/pre>\n<p>When you re-run SWIG once more, it will issue a warning<\/p>\n<pre><code>app\/src\/main\/cpp\/IAndroidActivity.h:23: Warning 473: Returning a pointer or reference in a director method is not recommended.<\/code><\/pre>\n<p>The warning is issued because, as we are returning a pointer, the Java object bound to this pointer may become invalid at any point of time &#8212; after the next Garbage Collector run. We have to make sure pointed Java Object will not be garbage collected by keeping its reference, as here, in implementation. We will talk about Garbage Collector in the <a href=\"#gc_ref_counting\" rel=\"noopener noreferrer nofollow\">next section<\/a>.<\/p>\n<pre><code class=\"java\">public class MainActivity extends AppCompatActivity {     \/\/ ...      private final ITaskScheduler taskScheduler = new TaskScheduler();      private class AndroidActivity extends IAndroidActivity     {         @Override         public ITaskScheduler getTaskScheduler()         {             return taskScheduler;         }          \/\/ ...     }      \/\/ ...<\/code><\/pre>\n<p>To overcome the warning, we can pass pointers directly to the functions, as with <code>void onCreate(IAndroidActivity* androidActivity);<\/code>. Even if you pass a not-referenced object to this function, it will definitely live until the function exits. Because such an object is the so-called JNI Local Reference. Ok, let&#8217;s run some async tasks in C++ (<code>ActivityModel.cpp<\/code>):<\/p>\n<pre><code class=\"cpp\">void doAsyncTasks(IAndroidActivity *androidActivity) {     ITaskScheduler *taskScheduler = androidActivity->getTaskScheduler();     __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());     taskScheduler->executeOnBackgroundThread(             [=]()             {                 __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());                 taskScheduler->executeOnUIThread(                         [=]()                         {                             __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());                         });             }); }  void ActivityModel::onCreate(IAndroidActivity *androidActivity) {     androidActivity->showToast(make_shared&lt;string>(\"Toast from C++\"));     androidActivity->sendMessage(make_shared&lt;message>(22, make_shared&lt;string>(\"Greetings!\")));     doAsyncTasks(androidActivity); }<\/code><\/pre>\n<p>Our C++ code doesn&#8217;t do anything except writing logs. From logs, we can see on which thread which lambda was executed. You can also see this from thread ids in logs <code>21342-21402<\/code>. The left is process id, the right is thread id; for the main thread they are equal.<\/p>\n<pre><code>2020-08-16 17:56:22.580 21342-21342\/? D\/ActivityModel: Is main thread: 1 2020-08-16 17:56:22.584 21342-21402\/? D\/ActivityModel: Is main thread: 0 2020-08-16 17:56:22.634 21342-21342\/? D\/ActivityModel: Is main thread: 1<\/code><\/pre>\n<p><a class=\"anchor\" name=\"gc_ref_counting\" id=\"gc_ref_counting\"><\/a><\/p>\n<h2>GC and Reference counting (or how to break the code)<\/h2>\n<p>Java GC and C++ <code>shared_ptr<\/code> doesn&#8217;t know about one another. Fin.<\/p>\n<p>With SWIG, when you pass your C++ object to Java, a reference to it will be kept. So, if you abandon your object in C++, Java is still able to use it. It&#8217;s not good to abandon normal pointers, of course:) But with <code>smart_ptr<\/code> or regular objects (non-pointers), you can just create them, send to Java, and forget. The object will be kept alive until Java is using it. You can even pass your Java object back to C++ and it will be fine.<\/p>\n<p>It gets complicated when you pass Java object inherited from C++ interface (director) to C++, you have to make sure Java object is <strong>valid<\/strong> when you using it. Java object is valid until it is Garbage Collected.<\/p>\n<h4>1. Your Java object is safe if you are using it in the scope of a function.<\/h4>\n<p>Even if you call it from Java as this:<\/p>\n<pre><code class=\"java\">activityModel.onCreate(new AndroidActivity());<\/code><\/pre>\n<p>Until <code>onCreate()<\/code> exits, your object will not be Garbage Collected. Your <code>new AndroidActivity()<\/code> object here is handled as a so-called JNI Local Reference. Usage in a scope of a function:<\/p>\n<pre><code class=\"cpp\">void ActivityModel::onCreate(IAndroidActivity *androidActivity) {     \/\/ Any usage of 'androidActivity' here is safe     androidActivity->showToast(make_shared&lt;string>(\"Toast from C++\"));     androidActivity->sendMessage(make_shared&lt;message>(22, make_shared&lt;string>(\"Greetings!\")));     doAsyncTasks(androidActivity);     sendPolymorphicMessage(androidActivity); }<\/code><\/pre>\n<p>If we store a pointer to <code>IAndroidActivity *androidActivity<\/code> anywhere, it will be eventually collected by GC. And we don&#8217;t know when it will happen. You will just get a crash or undefined behavior.<\/p>\n<h4>2. Your Java object is safe when you keeping a reference to it.<\/h4>\n<p>This is what we currently do with our <code>TaskScheduler<\/code> &#8212; we keeping reference.<\/p>\n<pre><code class=\"java\">public class MainActivity extends AppCompatActivity {     \/\/ ...     private final ITaskScheduler taskScheduler = new TaskScheduler();<\/code><\/pre>\n<p>But, <code>TaskScheduler<\/code> by its functionality (executing tasks) should have a longer lifecycle than <code>MainActivity<\/code>; if we have more activities, or on simple screen rotation event &#8212; activity will be destroyed, and reference to the old <code>TaskScheduler<\/code> lost. It eventually will be GC&#8217;d. Better to store <code>TaskScheduler<\/code> in the <code>Application<\/code> class, as it lives until the application will be destroyed. Or store it in the static variable.<\/p>\n<pre><code class=\"java\">public class App extends Application {     \/\/ ...     private final ITaskScheduler taskScheduler = new TaskScheduler();<\/code><\/pre>\n<p>Such an object as <code>ActivityModel<\/code>, holding the activity data and business logic can be stored in the scope of the <code>ViewModel<\/code> of particular <code>Activity<\/code>. In our case, it would be like.<\/p>\n<pre><code class=\"java\">public class MainViewModel extends ViewModel {     \/\/ ...     public final ActivityModel activityModel = new ActivityModel();<\/code><\/pre>\n<h4>2.1. Breaking the code.<\/h4>\n<p>To illustrate what happens when you lose the reference to the Java director object, let&#8217;s recall our C++ code from <code>ActivityModel.cpp<\/code>. We have a chain of lambda functions here. They are executed out of the scope of the <code>doAsyncTasks()<\/code> function.<\/p>\n<pre><code class=\"cpp\">void doAsyncTasks(IAndroidActivity *androidActivity) {     ITaskScheduler *taskScheduler = androidActivity->getTaskScheduler();     __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());     taskScheduler->executeOnBackgroundThread(             [=]()             {                 __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());                 taskScheduler->executeOnUIThread(                         [=]()                         {                             __android_log_print(ANDROID_LOG_DEBUG, TAG, \"Is main thread: %d\", taskScheduler->isMainThread());                         });             }); } \/\/ ... void ActivityModel::onCreate(IAndroidActivity *androidActivity) {     doAsyncTasks(androidActivity);     \/\/ ... }<\/code><\/pre>\n<p>And let&#8217;s alter our Java code a bit, to lose a reference, in <code>MainActivity.java<\/code>:<\/p>\n<pre><code class=\"java\">public class MainActivity extends AppCompatActivity {     \/\/ ...     private class AndroidActivity extends IAndroidActivity     {         \/\/ ...         @Override         public ITaskScheduler getTaskScheduler()         {             \/\/ return taskScheduler; \/\/ Delete this line              \/\/ Add this line             \/\/ Creates new object and not stores a reference             return new TaskScheduler();         }<\/code><\/pre>\n<p>And to delay the lambda execution to give enough time for GC to run, in <code>TaskScheduler.java<\/code><\/p>\n<pre><code class=\"java\">final class TaskScheduler extends ITaskScheduler {     private static final Handler mainThreadHandler = new Handler();     private static final ExecutorService backgroundTaskExecutor = Executors.newSingleThreadExecutor();     \/\/ ...     @Override     public void executeOnBackgroundThread(FunctorVoid function)     {         mainThreadHandler.postDelayed(() -> {             backgroundTaskExecutor.execute(function::call);         }, 10_000); \/\/ Delay task execution by 10 seconds     }<\/code><\/pre>\n<p>Now run the application, and exactly in 10 seconds, you will get a crash. You may actually need a few tries &#8212; GC is not guaranteed to run at any particular time. If still not got a crash &#8212; please increase time significantly. This shortened log of a crash points to our <code>std::function<\/code> wrapper.<\/p>\n<pre><code>08-17 21:15:09.634 15891 15924 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x6c6f675f6d6f73 in tid 15924 (pool-1-thread-1), pid 15891 (wigandroidguide) 08-17 21:15:09.778 15927 15927 F DEBUG   :     #03 pc 00000000000284dc  \/data\/app\/com.goldberg.swigandroidguide-Hs_uprJLKN1eGn1jdTm0eQ==\/lib\/arm64\/libnative-lib.so (std::__ndk1::function&lt;void ()=\"\">::operator()() const+160) 08-17 21:15:09.778 15927 15927 F DEBUG   :     #04 pc 000000000002842c  \/data\/app\/com.goldberg.swigandroidguide-Hs_uprJLKN1eGn1jdTm0eQ==\/lib\/arm64\/libnative-lib.so (Java_com_goldberg_swigandroidguide_swiggenerated_SwigAndroidGuideJNI_FunctorVoid_1call+48)<\/code><\/pre>\n<h4>3. Keep global reference using NewGlobalRef<\/h4>\n<p>You can call JNI function <code>NewGlobalRef<\/code> in C++ on Java object, this will keep a reference to it, even if you abandon the reference in Java. Then, when you are done with the object, release the reference calling <code>DeleteGlobalRef<\/code>. With SWIG it can be done via typemaps or another way. I didn&#8217;t do this, because this solution is <strong>unsafe<\/strong>, as this is manual memory management; much safer just to keep references. Also, there is a limited count of these references. Don&#8217;t know for now, but a few years ago it was about 512. It probably depends on the device&#8217;s VM settings.<\/p>\n<p><a class=\"anchor\" name=\"debug_swig\" id=\"debug_swig\"><\/a><\/p>\n<h2>Debugging SWIG<\/h2>\n<p><a class=\"anchor\" name=\"debug_swig_script\" id=\"debug_swig_script\"><\/a><\/p>\n<h3>Debugging SWIG script<\/h3>\n<p>For debugging SWIG script <code>run_swig.sh<\/code> and code generation process.<\/p>\n<ul>\n<li>\n<p>Use <code>-v<\/code> (Verbose) argument for verbose output.<\/p>\n<\/li>\n<li>\n<p>See other debug options by running <code>swig -help<\/code> in the terminal.<\/p>\n<\/li>\n<\/ul>\n<p>The line where the SWIG program is executed in <code>run_swig.sh<\/code> is the last line. The options you will have to add depends on your specific case.<\/p>\n<pre><code>swig -I${android_src_dir} -c++ -java -package com.goldberg.swigandroidguide.swiggenerated -o ${generated_cpp_file} -outdir ${generated_java_dir} SwigAndroidGuide.i<\/code><\/pre>\n<p><a class=\"anchor\" name=\"debug_generated_code\" id=\"debug_generated_code\"><\/a><\/p>\n<h3>Debugging generated code and runtime errors<\/h3>\n<h4>Observe SWIG-generated files<\/h4>\n<p>As mentioned in the chapter <a href=\"#swig_generated_files\" rel=\"noopener noreferrer nofollow\">Calling C++ from Java<\/a>, observe the files generated with SWIG (it is explained in the linked section).<\/p>\n<p>As mentioned <a href=\"#SWIGTYPE_\" rel=\"noopener noreferrer nofollow\">here<\/a>, you may get a file generated with the naming pattern <code>SWIGTYPE_<\/code>: <code>app\/src\/main\/java\/com\/goldberg\/swigandroidguide\/swiggenerated\/SWIGTYPE_p_std__string.java<\/code> Such a file means SWIG didn&#8217;t find a way to process your type. It does the basic <code>pointer<\/code> wrapping, and it will go through the language boundaries, but you will not be able to use your object.<\/p>\n<p>Exceptionally, for our <a href=\"#std_function_file\" rel=\"noopener noreferrer nofollow\">std::function<\/a> SWIG-generated file name patterns are:<\/p>\n<ul>\n<li>\n<p>incorrect: <code>SWIGTYPE_p_std__functionT_void_fF_t.java<\/code><\/p>\n<\/li>\n<li>\n<p>correct: <code>SWIGTYPE_p_f___void.java<\/code><\/p>\n<\/li>\n<\/ul>\n<h4>Check generated code<\/h4>\n<p>This usually doesn&#8217;t need for SWIG-generated code for arguments of simple types. But if you have added your custom typemaps, you may want to check what code was actually generated. Let&#8217;s walk through the process. At first, let&#8217;s write simple test for our function <code>setText(shared_ptr&lt;string>)<\/code> in <code>Message.h<\/code>. Edit <code>app\/build.gradle<\/code> (git diff shown):<\/p>\n<pre><code class=\"diff\">     implementation 'androidx.constraintlayout:constraintlayout:1.1.3' +    androidTestImplementation 'androidx.test:runner:1.3.0' +    androidTestImplementation 'androidx.test.ext:truth:1.3.0' +    androidTestImplementation 'androidx.test.ext:junit:1.1.2'  }<\/code><\/pre>\n<p>Create <code>app\/src\/androidTest\/java\/com\/goldberg\/swigandroidguide\/MessageTest.java<\/code>:<\/p>\n<pre><code class=\"java\">package com.goldberg.swigandroidguide;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import com.goldberg.swigandroidguide.swiggenerated.Message;  import org.junit.Test; import org.junit.runner.RunWith;  import static com.google.common.truth.Truth.assertThat;  @RunWith(AndroidJUnit4.class) public class MessageTest {     static     {         \/\/ Load C++ library.         \/\/ Alternatively it can be loaded in Application class,         \/\/ as an Android Application is created when executing Android tests.         System.loadLibrary(\"native-lib\");     }      @Test     public void test()     {         Message message = new Message();         message.setText(\"Have a nice day\");         assertThat(message.getText()).isEqualTo(\"Have a nice day\");     } }<\/code><\/pre>\n<p>Run this test, it will pass. But actually our <code>shared_ptr&lt;string><\/code> typemap is incomplete. Now let&#8217;s break it.<\/p>\n<pre><code class=\"java\">    @Test     public void test()     {         Message message = new Message();         message.setText(null);         assertThat(message.getText()).isNull();<\/code><\/pre>\n<p>When executing this test, we will get a crash (shortened and comments added; see Run window on Android Studio or logcat to see this output). The call stack is read bottom-to-top:<\/p>\n<pre><code class=\"cpp\">\/\/ Reason of the crash A\/wigandroidguid: java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: GetStringUTFChars received NULL jstring java_vm_ext.cc:542]     in call to GetStringUTFChars java_vm_ext.cc:542]     from void com.goldberg.swigandroidguide.swiggenerated.SwigAndroidGuideJNI.Message_setText(long, com.goldberg.swigandroidguide.swiggenerated.Message, java.lang.String) \/\/ ... \/\/ Place of crash runtime.cc:558]   native: #14 pc 0000000000031e18  \/data\/app\/com.goldberg.swigandroidguide-O2baaPk-eJTHZyu474aE9Q==\/lib\/arm64\/libnative-lib.so (_JNIEnv::GetStringUTFChars(_jstring*, unsigned char*)+64) \/\/ `???` seems to be our function `convertStringFromJavaToCpp` from the typemap runtime.cc:558]   native: #15 pc 000000000002ed7c  \/data\/app\/com.goldberg.swigandroidguide-O2baaPk-eJTHZyu474aE9Q==\/lib\/arm64\/libnative-lib.so (???) \/\/ Function in `swig-generated\/SwigAndroidGuide_wrap.cpp` runtime.cc:558]   native: #16 pc 000000000002eab8  \/data\/app\/com.goldberg.swigandroidguide-O2baaPk-eJTHZyu474aE9Q==\/lib\/arm64\/libnative-lib.so (Java_com_goldberg_swigandroidguide_swiggenerated_SwigAndroidGuideJNI_Message_1setText+164) \/\/ ... runtime.cc:558]   at com.goldberg.swigandroidguide.swiggenerated.SwigAndroidGuideJNI.Message_setText(Native method) \/\/ ... \/\/ Call to our function in Java runtime.cc:558]   at com.goldberg.swigandroidguide.swiggenerated.Message.setText(Message.java:56) runtime.cc:558]   at com.goldberg.swigandroidguide.MessageTest.test(MessageTest.java:27)<\/code><\/pre>\n<p>From this crash report we can clearly see that broken function is <code>setText(shared_ptr&lt;string>)<\/code> in <code>Message.h<\/code>. How we inverstigate this? At first, we need to know which typemap is failed. Typemap description tells us it should be the <code>%typemap(in) std::shared_ptr&lt;std::string><\/code> in <code>std_shared_ptr_to_string.i<\/code> typemap file we have used earlier:<\/p>\n<pre><code class=\"cpp\">\/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(in) std::shared_ptr&lt;std::string> {     $1 = convertStringFromJavaToCpp(jenv, $input); }<\/code><\/pre>\n<p>To know exactly, the simplest way is to modify the typemap and check if the generated code has changed.<\/p>\n<pre><code class=\"cpp\">\/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(in) std::shared_ptr&lt;std::string> {     \/\/ TYPEMAP START     $1 = convertStringFromJavaToCpp(jenv, $input);     \/\/ TYPEMAP END }<\/code><\/pre>\n<p>Run SWIG script <code>run_swig.sh<\/code> to re-generate the code. Check the generated code for this function in <code>SwigAndroidGuide_wrap.cpp<\/code>:<\/p>\n<pre><code class=\"cpp\">SWIGEXPORT void JNICALL Java_com_goldberg_swigandroidguide_swiggenerated_SwigAndroidGuideJNI_Message_1setText( JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jstring jarg2) {   SwigAndroidGuide::Message *arg1 = (SwigAndroidGuide::Message *) 0 ;   std::shared_ptr&lt; std::string > arg2 ;   std::shared_ptr&lt; SwigAndroidGuide::Message > *smartarg1 = 0 ;    (void)jenv;   (void)jcls;   (void)jarg1_;    smartarg1 = *(std::shared_ptr&lt;  SwigAndroidGuide::Message > **)&amp;amp;jarg1;   arg1 = (SwigAndroidGuide::Message *)(smartarg1 ? smartarg1->get() : 0);    {     \/\/ TYPEMAP START     arg2 = convertStringFromJavaToCpp(jenv, jarg2);     \/\/ TYPEMAP END   }   (arg1)->setText(arg2); }<\/code><\/pre>\n<p>Our newly added comments are here, it means we picked the right typemap. We know <code>GetStringUTFChars<\/code> with null argument caused a crash. It is in our conversion function in <code>std_shared_ptr_to_string.i<\/code>.<\/p>\n<pre><code class=\"cpp\">std::shared_ptr&lt;std::string> convertStringFromJavaToCpp(JNIEnv *jenv, jstring javaString) {     const char * psz_string = jenv->GetStringUTFChars(javaString, NULL); \/\/ Crash happened at this line     if (!psz_string)     {         return nullptr;     }      std::shared_ptr&lt;std::string> cppString = std::make_shared&lt;std::string>(psz_string);     jenv->ReleaseStringUTFChars(javaString, psz_string);     return cppString; }<\/code><\/pre>\n<p>Let&#8217;s fix it by handling the null argument.<\/p>\n<pre><code class=\"cpp\">std::shared_ptr&lt;std::string> convertStringFromJavaToCpp(JNIEnv *jenv, jstring javaString) {     if (!javaString) return nullptr; \/\/ &lt; Add this line      const char * psz_string = jenv->GetStringUTFChars(javaString, NULL);<\/code><\/pre>\n<p>Run SWIG script <code>run_swig.sh<\/code> to re-generate the code. Now run an Android test. It will pass. We were making changes to the typemap and re-generated the code because the problem was very simple. But for the more complex problem, you can edit the SWIG-generated code directly to find the solution faster, without the need to re-generate wrapper, and then implement it in the typemap.<\/p>\n<p>Congratulations! Now you know how to debug SWIG-generated code. We have handled only the case on the C++ side. But when Java-side broke, the approach is exactly the same; the only difference is that you have to debug code generated on the Java side.<\/p>\n<p>You can also run a project in Debug mode when needed to see variable values, go step-by-step, etc.<\/p>\n<p><a class=\"anchor\" name=\"misc\" id=\"misc\"><\/a><\/p>\n<h2>Misc<\/h2>\n<p>If you don&#8217;t want to process some of your C++ code with SWIG, use <code>#ifndef SWIG<\/code> in the C++ code. The case may be, that you don&#8217;t need or don&#8217;t want to reveal some functions to Java, while they may be used on the C++ side and have to be in the <code>public:<\/code> section.<\/p>\n<h2>Conclusion<\/h2>\n<p>That&#8217;s all.<\/p>\n<p>In this\u00a0<em>part 2<\/em>, I covered complex situations when using SWIG, and cases someone may call &#171;weird&#187;. I&#8217;ve made hints on how to break the code (and how to not) and how to debug SWIG.<\/p>\n<p>The use-case of SWIG is quite narrow, as there are many simpler ways for cross-platform development, but I hope someone will found this tutorial and especially the practical bits &amp; <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\" rel=\"noopener noreferrer nofollow\">project<\/a> useful.<\/p>\n<p>Best regards, and thank you for reading!<\/p>\n<p><a class=\"anchor\" name=\"resources\" id=\"resources\"><\/a><\/p>\n<h2>Resources<\/h2>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\" rel=\"noopener noreferrer nofollow\">Android Studio project<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps\" rel=\"noopener noreferrer nofollow\">SWIG documentation &#8212; Java typemaps<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps_c_to_java_types\" rel=\"noopener noreferrer nofollow\">SWIG documentation &#8212; C++ &amp; Director typemaps<\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/536868\/\"> https:\/\/habr.com\/ru\/articles\/536868\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><em>This is Part 2. Part 1 is\u00a0<\/em><a href=\"https:\/\/habr.com\/ru\/post\/536314\/\" rel=\"noopener noreferrer nofollow\"><em>here<\/em><\/a><em>.<\/em><\/p>\n<p><em>Part 2<\/em>\u00a0covers the use of typemaps, complex &amp; weird cases, and debugging suggestions. This part requires an understanding of Part 1 &#8212; usage of\u00a0<a href=\"http:\/\/swig.org\/\" rel=\"noopener noreferrer nofollow\">SWIG<\/a>\u00a0in simple cases.<\/p>\n<p>This is a practical guide, with <a href=\"https:\/\/github.com\/Mr-Goldberg\/SwigAndroidGuide\" rel=\"noopener noreferrer nofollow\">Android Studio project<\/a> you can play with.<\/p>\n<h3>Table of contents<\/h3>\n<ul>\n<li>\n<p><a href=\"#complex_cases\" rel=\"noopener noreferrer nofollow\">Complex cases<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#ptr_to_string\" rel=\"noopener noreferrer nofollow\">Shared pointer to std::string (C++ side typemaps)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#java_date_time_t\" rel=\"noopener noreferrer nofollow\">Java Date and C++ time_t (Java-side typemaps)<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#more_complexity\" rel=\"noopener noreferrer nofollow\">More complexity (all the weirdness)<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#byte_array_2d\" rel=\"noopener noreferrer nofollow\">Shared pointer to vector of shared pointers to vectors of bytes<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#std_function\" rel=\"noopener noreferrer nofollow\">std::function<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#gc_ref_counting\" rel=\"noopener noreferrer nofollow\">GC and Reference counting (or how to break the code)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#debug_swig\" rel=\"noopener noreferrer nofollow\">Debugging SWIG<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#debug_swig_script\" rel=\"noopener noreferrer nofollow\">Debugging SWIG script<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#debug_generated_code\" rel=\"noopener noreferrer nofollow\">Debugging generated code and runtime errors<\/a> <\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><a href=\"#misc\" rel=\"noopener noreferrer nofollow\">Misc<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#resources\" rel=\"noopener noreferrer nofollow\">Resources<\/a><\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"complex_cases\" id=\"complex_cases\"><\/a><\/p>\n<h2>Complex cases<\/h2>\n<p>This section covers the typemaps. <\/p>\n<p><a class=\"anchor\" name=\"ptr_to_string\" id=\"ptr_to_string\"><\/a><\/p>\n<h3>Shared pointer to std::string (C++ side typemaps)<\/h3>\n<p>Scheme<\/p>\n<pre><code class=\"cpp\">%shared_ptr(std::string);<\/code><\/pre>\n<p>just doesn&#8217;t seem to be working \u00af\\_(\u30c4)_\/\u00af &#8212; the generated code will not compile. Because SWIG, when generating a wrapper for <code>shared_ptr<\/code> arguments, expects that they are SWIG-wrapped types and relies on SWIG-generated functions, which are not part of the <code>java.lang.String<\/code> class that we expect to use on the Java side. We have to create our own typemap to allow <code>std::shared_ptr&lt;std::string><\/code>. Typemap instructs SWIG on how to process a particular type. I will not dig into deep details, see <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps\" rel=\"noopener noreferrer nofollow\">Java typemaps chapter<\/a>, especially <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps_c_to_java_types\" rel=\"noopener noreferrer nofollow\">C++ typemaps<\/a> and <a href=\"http:\/\/www.swig.org\/Doc4.0\/SWIGDocumentation.html#Java_typemaps_c_to_java_types\" rel=\"noopener noreferrer nofollow\">Director-specific typemaps<\/a> within the chapter.<\/p>\n<p><a class=\"anchor\" name=\"table_1\" id=\"table_1\"><\/a><\/p>\n<p>Look to the following table for a simpler understanding of the typemaps (description is below the table).<\/p>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th data-colwidth=\"50\" width=\"50\">\n<\/th>\n<th data-colwidth=\"128\" width=\"128\">\n<p>Type in level<\/p>\n<\/th>\n<th data-colwidth=\"92\" width=\"92\">\n<p>Type 1<\/p>\n<\/th>\n<th data-colwidth=\"80\" width=\"80\">\n<p>Type 2<\/p>\n<\/th>\n<th data-colwidth=\"90\" width=\"90\">\n<p>Type 3<\/p>\n<\/th>\n<th>\n<p>Typemaps between levels<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>1<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>Java<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>String<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>Date<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>byte[][]<\/p>\n<\/td>\n<td>\n<p>%typemap(jstype)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>%typemap(javain\u2193|javaout\u2191|javadirectorin\u2191|javadirectorout\u2193]<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>2<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>Java intermediary<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>String<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>long<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>byte[][]<\/p>\n<\/td>\n<td>\n<p>%typemap(jtype)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>Automatically done by JNI (no typemap)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>3<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>JNI (C++ intermediary)<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>jstring<\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>jlong<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>jobjectArray<\/p>\n<\/td>\n<td>\n<p>%typemap(jni)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<\/td>\n<td>\n<p>%typemap(in\u2193|out\u2191|directorin\u2191|directorout\u2193)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"50\" width=\"50\">\n<p>4<\/p>\n<\/td>\n<td data-colwidth=\"128\" width=\"128\">\n<p>C++<\/p>\n<\/td>\n<td data-colwidth=\"92\" width=\"92\">\n<p>std::shared_ptr&lt;std::string><\/p>\n<\/td>\n<td data-colwidth=\"80\" width=\"80\">\n<p>time_t (equals) long long<\/p>\n<\/td>\n<td data-colwidth=\"90\" width=\"90\">\n<p>shared_<em>ptr&lt;vector&lt;shared_<\/em>ptr&lt;vector&lt;byte>>>><\/p>\n<\/td>\n<td>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>To pass anything between C++ and JAVA, back or forth, you need to go through the four levels. Levels 1 and 4 are Java and C++ &#8212; the levels you are writing business logic at. To go from 1 to 4 or back you have to pass 3 levels of conversion. 2->3 and back is done by JNI. But 1->2 and 3->4 and back are done by the typemaps. Some typemaps are defining types to operate on, in the table, they are residing on the lines with numbers (levels). Some typemaps are defining level and direction, at which they will convert type (between lines with numbers); arrow explains in which direction the particular typemap is working. Note that regular and director typemaps directions are flipped, i.e. <code>%typemap(in)<\/code> doing the same operation as <code>%typemap(directorout)<\/code>. For example, <code>%typemap(in) std::shared_ptr&lt;std::string><\/code> is converting level 3->4; level 4 C++ type is defined in this typemap; level 3 JNI type <code>jstring<\/code> is defined by another typemap: <code>%typemap(jni) std::shared_ptr&lt;std::string> \"jstring\"<\/code>. The table also covered the <code>Date<\/code> and <code>byte[][]<\/code> type, we will talk about them in the later chapters.<\/p>\n<p>It might sound complicated, but you will eventually get how everything is working while practicing. Read the comments in the following snippet, they are explaining everything in place.  So, to proceed, crate new file <code>swig\/std_shared_ptr_to_string.i<\/code> and fill it with content.<\/p>\n<pre><code class=\"cpp\">%include &lt;std_shared_ptr.i> %include &lt;std_string.i>  %{ #include &lt;memory> #include &lt;string> %}  namespace std {     \/\/ To properly recognize type defined in our Types.h     %template(shared_ptr_to_string) std::shared_ptr&lt;std::string>; }  %{ namespace {     std::shared_ptr&lt;std::string> convertStringFromJavaToCpp(JNIEnv *jenv, jstring javaString)     {         const char * psz_string = jenv->GetStringUTFChars(javaString, NULL);         if (!psz_string)         {             return nullptr;         }          std::shared_ptr&lt;std::string> cppString = std::make_shared&lt;std::string>(psz_string);         jenv->ReleaseStringUTFChars(javaString, psz_string);         return cppString;     }      jstring convertStringFromCppToJava(JNIEnv *jenv, std::shared_ptr&lt;std::string> cppString)     {         if (!cppString)         {             return nullptr;         }          return jenv->NewStringUTF(cppString->c_str());     } } %}  \/\/ \/\/ Type definitions for C type 'std::shared_ptr&lt;std::string>' \/\/  %typemap(jstype) std::shared_ptr&lt;std::string> \"java.lang.String\" \/\/ Java type %typemap(jtype) std::shared_ptr&lt;std::string> \"java.lang.String\" \/\/ Java intermediary type %typemap(jni) std::shared_ptr&lt;std::string> \"jstring\" \/\/ JNI C type (or intermediary C type)  \/\/ \/\/ Java-side typemaps \/\/  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) %typemap(javain) std::shared_ptr&lt;std::string> \"$javainput\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) %typemap(javaout) std::shared_ptr&lt;std::string> {      return $jnicall; }  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) for director methods %typemap(javadirectorout) std::shared_ptr&lt;std::string> \"$javacall\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) for director methods %typemap(javadirectorin) std::shared_ptr&lt;std::string> \"$jniinput\"  \/\/ \/\/ C++ side typemaps \/\/  \/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(in) std::shared_ptr&lt;std::string> {     $1 = convertStringFromJavaToCpp(jenv, $input); }  \/\/ Conversion from C++ type to 'jni' (JNI C type) %typemap(out) std::shared_ptr&lt;std::string> {     return convertStringFromCppToJava(jenv, $1); }  \/\/ Conversion from 'jni' (JNI C type) to C++ type for director methods %typemap(directorout) std::shared_ptr&lt;std::string> {     $result = convertStringFromJavaToCpp(jenv, $input); }  \/\/ Conversion from C++ type to 'jni' (JNI C type) for director methods \/\/ Note: Ljava\/lang\/String; is the JNI field descriptor for the Java String type %typemap(directorin,descriptor=\"Ljava\/lang\/String;\") std::shared_ptr&lt;std::string> {     $input = convertStringFromCppToJava(jenv, $1); }<\/code><\/pre>\n<p>Include this file into your SWIG interface file:<\/p>\n<pre><code class=\"cpp\">%module(directors=\"1\") SwigAndroidGuide  %include &lt;std_shared_ptr.i> %include &lt;std_string.i> %include \"std_shared_ptr_to_string.i\" \/\/ &lt;&lt; Add this line<\/code><\/pre>\n<p>Re-run SWIG script <code>run_swig.sh<\/code> and you will be able to run your application.<\/p>\n<p>Note that I&#8217;ve created separate conversion functions, which are used in the typemaps. This allows:<\/p>\n<ul>\n<li>\n<p>Writing clear C++ code; note, you have to use <code>$input<\/code> and similar constructions in typemap body;<\/p>\n<\/li>\n<li>\n<p>You know what exactly C++ function is doing by giving it a proper name;<\/p>\n<\/li>\n<li>\n<p>Typemaps are looking clearer (and you know what they are doing by reading C++ function names);<\/p>\n<\/li>\n<li>\n<p>Re-use these functions, as regular and director typemaps are the same in most of the cases;<\/p>\n<\/li>\n<li>\n<p>Decrease in code size. Each time you use the argument particular typemap is working with, the typemap code will be copy-pasted into the SWIG-generated file. This increases code size, which is not great for mobile devices.<\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"java_date_time_t\" id=\"java_date_time_t\"><\/a><\/p>\n<h3>Java Date and C++ time_t (Java-side typemaps)<\/h3>\n<p>For <code>java.util.Date<\/code> it is much simpler to write such typemaps on the Java side, to avoid unnecessary JNI calls in C++. See <a href=\"#table_1\" rel=\"noopener noreferrer nofollow\">Table 1<\/a> to see how we map Date type to C++. In C++ it will be the <code>time_t<\/code>, which is <code>long long<\/code>.<\/p>\n<p>Let&#8217;s add the creation date to our message, in <code>Message.h<\/code>:<\/p>\n<pre><code class=\"cpp\">class Message { public:     \/\/ Add these lines     time_t getCreationDate() const { return _creationDate; }     void setCreationDate(time_t creationDate) { _creationDate = creationDate; } private:      time_t _creationDate; \/\/ &lt; Add this line<\/code><\/pre>\n<p>If you run SWIG script <code>run_swig.sh<\/code> now, you will notice the new file:<\/p>\n<pre><code>\/app\/src\/main\/java\/com\/goldberg\/swigandroidguide\/swiggenerated\/SWIGTYPE_p_time_t.java<\/code><\/pre>\n<p>and new functions in WSIG-generated <code>Message.java<\/code>:<\/p>\n<pre><code class=\"java\">public SWIGTYPE_p_time_t getCreationDate() {   return new SWIGTYPE_p_time_t(SwigAndroidGuideJNI.Message_getCreationDate(swigCPtr, this), true); }  public void setCreationDate(SWIGTYPE_p_time_t creationDate) {   SwigAndroidGuideJNI.Message_setCreationDate(swigCPtr, this, SWIGTYPE_p_time_t.getCPtr(creationDate)); }<\/code><\/pre>\n<p>This means, as you guess, that the type <code>time_t<\/code> can&#8217;t be handled properly.<\/p>\n<p>Let&#8217;s add new SWIG file <code>swig\/time_t.i<\/code>. We do only assignments for the C++ portion of the typemaps. But java typemaps are including the actual Java code. Note, I didn&#8217;t create separate function as I did in C++, because code is very simple. One more reason &#8212; one Java file is generated for each SWIG-wrapped class, so it is just harder to do than in C++, where everything is in one large *.cpp file.<\/p>\n<pre><code class=\"cpp\">\/\/ \/\/ Type definitions for C type 'time_t' \/\/  %typemap(jstype) time_t \"java.util.Date\" \/\/ Java type %typemap(jtype) time_t \"long\" \/\/ Java intermediary type %typemap(jni) time_t \"jlong\" \/\/ JNI C type (or intermediary C type)  \/\/ \/\/ Java-side typemaps \/\/  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) %typemap(javain) time_t \"$javainput.getTime() \/ 1000\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) %typemap(javaout) time_t {     return new java.util.Date($jnicall * 1000); }  \/\/ Conversion from 'jstype' (Java type) to 'jtype' (Java intermediary type) for director methods %typemap(javadirectorin) time_t \"new java.util.Date($jniinput * 1000)\"  \/\/ Conversion from 'jtype' (Java intermediary type) to 'jstype' (Java type) for director methods %typemap(javadirectorout) time_t \"$javacall.getTime() \/ 1000\"  \/\/ \/\/ C++ side typemaps \/\/ All the typemaps are just an assignments. \/\/  %typemap(in) time_t \"$1 = $input;\" \/\/ Conversion from 'jni' (JNI C type) to C++ type %typemap(out) time_t \"$result = $1;\" \/\/ Conversion from C++ type to 'jni' (JNI C type)  \/\/ Conversion from 'jni' (JNI C type) to C++ type for director methods %typemap(directorout) time_t \"$result = $input;\"  \/\/ Conversion from C++ type to 'jni' (JNI C type) for director methods \/\/ Note: Ljava\/lang\/String; is the JNI field descriptor for the Java String type %typemap(directorin, descriptor = \"Ljava\/util\/Date;\") time_t \"$input = $1;\"<\/code><\/pre>\n<p>Include this file into SWIG instructions file <code>SwigAndroidGuide.i<\/code>:<\/p>\n<pre><code class=\"cpp\">%m<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-381970","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/381970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=381970"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/381970\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=381970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=381970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=381970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}