{"id":18,"date":"2007-11-29T08:37:47","date_gmt":"2007-11-28T21:14:28","guid":{"rendered":""},"modified":"2017-03-07T16:18:33","modified_gmt":"2017-03-07T16:18:33","slug":"paludis_meets_java_part_iii","status":"publish","type":"post","link":"https:\/\/blogs.gentoo.org\/ferdy\/2007\/11\/29\/paludis_meets_java_part_iii\/","title":{"rendered":"Paludis meets Java, part III"},"content":{"rendered":"<p>Once we&#8217;ve converted native types we face the task of converting arbitrary classes and types. Another thing we&#8217;ll need is extract the C++ type of a Java object (<tt>jobject<\/tt> in JNI).<\/p>\n<p>For that task, we will follow the convention of calling the native pointers in Java classes <tt>_ptr<\/tt>. With that, we can define the following templates:<\/p>\n<pre>template &lt;typename T_&gt;\r\ninline T_ * get_native_ptr(JNIEnv * env, const char * const class_name, jobject obj)\r\n{\r\n    jclass cls(env-&gt;FindClass(class_name));\r\n    jfieldID ptr_field(env-&gt;GetFieldID(cls, \"_ptr\", \"J\"));\r\n    jlong ptr(env-&gt;GetLongField(obj, ptr_field));\r\n    env-&gt;DeleteLocalRef(cls);\r\n    return from_java_ptr&lt;T_&gt;(ptr);\r\n}\r\n\r\ntemplate &lt;typename T_&gt;\r\ninline tr1::shared_ptr&lt;T_&gt; get_native_sptr(JNIEnv * env, const char * const class_name, jobject obj)\r\n{\r\n    jclass cls(env-&gt;FindClass(class_name));\r\n    jfieldID ptr_field(env-&gt;GetFieldID(cls, \"_ptr\", \"J\"));\r\n    jlong ptr(env-&gt;GetLongField(obj, ptr_field));\r\n    env-&gt;DeleteLocalRef(cls);\r\n    return from_java_ptr_sptr&lt;T_&gt;(ptr);\r\n}<\/pre>\n<p>This should really be doing more error checking, but it is good enough for ilustrating how nice are things when using proper tools (both languages and libraries).<\/p>\n<p>Converting arbitrary types also uses some template magic:<\/p>\n<pre>template &lt;typename T_&gt;\r\nstruct NativeToJavaTypeMapper\r\n{\r\n    jobject operator() (JNIEnv *, const T_ &amp;);\r\n};<\/pre>\n<p>Now we need specializations for each type we want to convert, for instance, converting a paludis&#8217; <tt>FSEntry<\/tt> into a <tt>java.io.File<\/tt> looks like the following:<\/p>\n<pre>template&lt;&gt;\r\nstruct NativeToJavaTypeMapper&lt;FSEntry&gt;\r\n{\r\n    jobject operator() (JNIEnv * env, const FSEntry &amp; f)\r\n    {\r\n        jclass cls(env-&gt;FindClass(\"java\/io\/File\"));\r\n        jmethodID constructor(env-&gt;GetMethodID(cls, \"&lt;init&gt;\", \"(Ljava\/lang\/String;)V\"));\r\n        jobject ret(env-&gt;NewObject(cls, constructor, to_java_string(env, stringify(f))));\r\n        env-&gt;DeleteLocalRef(cls);\r\n        return ret;\r\n    }\r\n};<\/pre>\n<p>Neat and clean.<\/p>\n<p>For containers, a <tt>java.util.LinkedList<\/tt> would be used for paludis&#8217; <tt>Sequence<\/tt>; and <tt>java.util.TreeSet<\/tt> for paludis&#8217; <tt>Set<\/tt>:<\/p>\n<pre>template &lt;typename T_, typename It_&gt;\r\njobject range_to_list(JNIEnv * env, It_ begin, It_ end)\r\n{\r\n    jclass list_class(env-&gt;FindClass(\"java\/util\/LinkedList\"));\r\n    jmethodID constructor(env-&gt;GetMethodID(list_class, \"&lt;init&gt;\", \"()V\"));\r\n    jobject our_list(env-&gt;NewObject(list_class, constructor));\r\n    jmethodID add_method(env-&gt;GetMethodID(list_class, \"add\", \"(Ljava\/lang\/Object;)Z\"));\r\n\r\n    for (It_ i(begin) ; i != end ; ++i)\r\n        env-&gt;CallBooleanMethod(our_list, add_method, NativeToJavaTypeMapper&lt;T_&gt;()(env, *i));\r\n\r\n    env-&gt;DeleteLocalRef(list_class);\r\n\r\n    return our_list;\r\n}\r\n\r\ntemplate &lt;typename T_, typename It_&gt;\r\njobject range_to_set(JNIEnv * env, It_ begin, It_ end)\r\n{\r\n    jclass set_class(env-&gt;FindClass(\"java\/util\/TreeSet\"));\r\n    jmethodID constructor(env-&gt;GetMethodID(set_class, \"&lt;init&gt;\", \"()V\"));\r\n    jobject our_set(env-&gt;NewObject(set_class, constructor));\r\n    jmethodID add_method(env-&gt;GetMethodID(set_class, \"add\", \"(Ljava\/lang\/Object;)Z\"));\r\n\r\n    for (It_ i(begin) ; i != end ; ++i)\r\n        env-&gt;CallBooleanMethod(our_set, add_method, NativeToJavaTypeMapper&lt;T_&gt;()(env, *i));\r\n\r\n    env-&gt;DeleteLocalRef(set_class);\r\n\r\n    return our_set;\r\n}<\/pre>\n<p>And now defining <tt>NativeToJavaTypeMapper<\/tt> specializations for containers is quite easy:<\/p>\n<pre>template&lt;&gt;\r\ntemplate &lt;typename T_&gt;\r\nstruct NativeToJavaTypeMapper&lt;tr1::shared_ptr&lt;const Sequence&lt;T_&gt; &gt; &gt;\r\n{\r\n    jobject operator() (JNIEnv * env, const tr1::shared_ptr&lt;const Sequence&lt;T_&gt; &gt; &amp; s)\r\n    {\r\n        return range_to_list&lt;T_&gt;(env, s-&gt;begin(), s-&gt;end());\r\n    }\r\n};\r\n\r\ntemplate&lt;&gt;\r\ntemplate &lt;typename T_&gt;\r\nstruct NativeToJavaTypeMapper&lt;tr1::shared_ptr&lt;const Set&lt;T_&gt; &gt; &gt;\r\n{\r\n    jobject operator() (JNIEnv * env, const tr1::shared_ptr&lt;const Set&lt;T_&gt; &gt; &amp; s)\r\n    {\r\n        return range_to_set&lt;T_&gt;(env, s-&gt;begin(), s-&gt;end());\r\n    }\r\n};<\/pre>\n<p>I&#8217;ve spent a fair amount of the time fighting with make and the build system. It looks mostly sane now, though.<\/p>\n<p>Dealing with exceptions has been a bit tricky, however, I think I have a good <i>system<\/i> to deal with it now, even  though Ciaran tagged it as <i>icky<\/i> and <i>ugly<\/i> <tt>\ud83d\ude42<\/tt>. That&#8217;d be the topic of the next part of the series.<\/p>\n<p>The documentation is currently at http:\/\/dev.gentoo.org\/~ferdy\/paludis-jni\/ . All of that has been accomplished in:<\/p>\n<pre>[ $ ~\/git\/paludis\/jni(jni) ] git diff --shortstat trunk..\r\n 65 files changed, 4371 insertions(+), 0 deletions(-)<\/pre>\n<p>Which is not a lot of code for what&#8217;s exposed.<\/p>\n<p>&mdash; ferdy<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once we&#8217;ve converted native types we face the task of converting arbitrary classes and types. Another thing we&#8217;ll need is extract the C++ type of a Java object (jobject in JNI). For that task, we will follow the convention of calling the native pointers in Java classes _ptr. With that, we can define the following &hellip; <a href=\"https:\/\/blogs.gentoo.org\/ferdy\/2007\/11\/29\/paludis_meets_java_part_iii\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Paludis meets Java, part III<\/span><\/a><\/p>\n","protected":false},"author":14,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3,6],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/posts\/18"}],"collection":[{"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/comments?post=18"}],"version-history":[{"count":1,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/posts\/18\/revisions"}],"predecessor-version":[{"id":37,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/posts\/18\/revisions\/37"}],"wp:attachment":[{"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/media?parent=18"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/categories?post=18"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/ferdy\/wp-json\/wp\/v2\/tags?post=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}