JNI etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
JNI etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

28 Kasım 2018 Çarşamba

JNI - Java'dan CPP'yi çağırmak

Giriş
Cpp kodu şöyledir.
JNIEXPORT MethodReturnType JNICALL Java_fullclassname_methodname
Diğer
Java'dan çağırmak için
1. Java kodu içinde
public static native MethodReturnType MethodName(MethodParameters);
şeklinde metod tanımlamaları yapılır.
2. Java kodu içinde System.loadLibrary() çağrısı ile .dll veya .so yüklenir.
3. fullclassname ile sınıf yaratılır ve metodu çağrılır

Örnek - Java'dan CPP Üretmek
Elimizde şöyle bir Java kodu olsun
package sample;

public class CalculateMath {
  static {
    System.loadLibrary("mathlib");
  }
  public native int calcSquare(int n);
}
Header dosyası üretmek için şöyle yaparız
javac -h . sample/CalculateMath.java
Üretilen sample_CalculateMath.h dosyası şöyledir
include <jni.h>
/* Header for class sample_CalculateMath */
                        
#ifndef _Included_sample_CalculateMath
#define _Included_sample_CalculateMath
#ifdef __cplusplus
extern "C" {
#endif

  /*
   * Class:     sample_CalculateMath
   * Method:    calcSquare
   * Signature: (I)I
   */
  JNIEXPORT jint JNICALL Java_sample_CalculateMath_calcSquare (JNIEnv *, jobject, jint);
        
#ifdef __cplusplus
}
#endif
#endif
CalculateMath.c dosyasının içini dolduralım
#include "sample_CalculateMath.h"
#include <string.h>

JNIEXPORT jint JNICALL Java_sample_CalculateMath_calcSquare
  (JNIEnv *env, jobject obj, jint num) {
   return num * num;
}

void main(){}
libmathlib.so ismide bir shared object derleyim
gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libmathlib.so
CalculateMath.c
Örnek
Java kodu şöyle olsun.
public class JNItest2 {

public native void helloworld(String[] args);

  static{
    System.loadLibrary("Dense");        
  }
  public static void main(String[] args)
  {        
    new JNItest2().helloworld(args);
  }
}
C metod ismi Java ile başlar, Java sınıf ismi eklenir, metod ismi eklenir. 
İlk parametre JNIEnv, 
İkinci parametre metodu ihtiva eden nesnedir. Eğer metod static ise bu parametreye gerek yok. 
Diğer parametreler metoda geçilen değerler. 

Şöyle yaparız.
JNIEXPORT void JNICALL
Java_JNItest2_helloworld(JNIEnv *env,jobject object, jobjectArray args)
{
...
}   
Örnek
Şöyle yaparız.
#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_android_app_aesKeyFromJNI(JNIEnv *env, jobject /* this */) {
    std::string secret = "somesecretkey";
    return env->NewStringUTF(secret.c_str());
}
Örnek
Şöyle yaparız.
JNIEXPORT jlong JNICALL Java_com_mypackage_ClipboardHelper_initialize
    (JNIEnv *env, jclass obj, jstring arg) {
Örnek
Şöyle yaparız.
header dosyasında şu include yapılır
#include <jni.h>
cpp şuna benzer.
JNIEXPORT jstring JNICALL Java_six_pack_Neatifier_neatify(JNIEnv* env, 
                                                          jclass clazz, 
                                                          jlong val, 
                                                          jchar pad, 
                                                          jint span)
{
   ... 
   jstring ret = env->NewStringUTF(out);
   return ret;
}
Java'dan DLL'i yükleriz.
System.load(System.getProperty("user.dir") + File.separator +
                        "src" + File.separator + "mylib.jnilib");
Java içinde Cpp ile aynı imzayı taşıyan bir metod tanımlarız.
public static native String neatify(final long val,
                                    final char pad,
                                    final int span);
Metodu çağırırız.
neatify(l, '_', 3);
Örnek
Elimizde şöyle bir java kodu olsun. HashMap parametre olarak metoda geçiliyor.
import java.util.*;  
class javasam{  
  private native void print(HashMap<String,String> hm);
  public static void main(String args[]){  
    HashMap<String,String> hm=new HashMap<String,String>();   
    hm.put("100","Amit");  
    hm.put("101","Vijay");  
    hm.put("102","Rahul");  
    new javasam().print(hm);
  }  
  static {
    System.loadLibrary("javasam");
  }  
}
cpp kodu şöyle olsun. Parametre olarak geçilen nesneye erişiliyor.
#include "stdafx.h"
#include <stdio.h>
#include <jni.h>
#include "javasam.h"
#include <string.h>
#include <map>
#include <iostream>
JNIEXPORT void JNICALL Java_javasam_print (JNIEnv *s, jobject k, jobject l)
{
  jclass mapclass = s->GetObjectClass(l);
  ...
}

10 Temmuz 2018 Salı

JNI

Giriş
Açıklaması şöyle
It is the interface which interacts with the Native Method libraries and provides the native libraries (C, C++) required for the execution. It enables JVM to call C/C++ libraries and to be called by C/C++ libraries which may be specific to hardware.
Bu arayüz aracılığıyla
1. Java'dan C/C++ kodları çağrılabilir. Java'dan CPP'yi çağırmak yazısına bakabilirsiniz
2. C+C++'tan Java çağrılabilir. JNI - C kodundan Java'yı çağırmak yazısına bakabilirsiniz

Not : Şöyle bir soru ve cevap var. JNI için bir alias yöntemi nasıl uygulanır bilmiyorum
Q : Which language's style guidelines should be used when writing code that is supposed to be called from another language?
A : In general: when you write some library in language 1, you use the conventions from language 1, and use the alias mechanisms from language 2 to provide an API to map the function names to the case conventions of language 2.

Önemli Sınıflar
2. JavaVM Sınıfı


JNI Tipleri
Şöyle
jboolean , jchar, jint,  jlong , jobject, jobjectArray, jIntArray, jclass


11 Ocak 2018 Perşembe

JNI JNIEnv Sınıfı

Giriş
Bu sınıf JNI'da kullanılan belki de en önemli sınıf.

CallVoidMethod metodu
Şöyle yaparız.
jobject runnable = ...;
jmethodID mid = ...;
env->CallVoidMethod(runnable, mid);
FindClass metodu
C kodundan Java kodunu çağırırken, Java sınıfını bulmak için kullanılır.
Örnek
Şöyle yaparız.
bool load(const char* classFile)
{   
  JNIEnv* env = ...;
  auto javacls = env->FindClass(classFile);
  if (javacls == nullptr)
  {
    env->ExceptionDescribe();
    return false;
  }
  ...
  return true;
}
Örnek
HashMap nesnesi yaratmak için şöyle yaparız.
jclass hashMapClass= env->FindClass(env, "java/util/HashMap");
jmethodID hashMapInit = env->GetMethodID(env, hashMapClass, "<init>", "(I)V");
jobject hashMapObj = env->NewObject(env, hashMapClass, hashMapInit, mMap.size());
GetArrayLength metodu
Java kodu şöyle olsun.
String[] args = ...;
new JNItest2().helloworld(args);
C kodunda şöyle yaparız.
JNIEXPORT void JNICALL
Java_JNItest2_helloworld(JNIEnv *env,jobject object, jobjectArray args)
{
  int argc = env->GetArrayLength(args);   
}
GetMethodID metodu
C kodundan Java kodunu çağırırken, Java sınıfının metodunu bulmak için kullanılır. Java metod imzaları için kullanılan tablo şöyle.
Type Signature Java Type
1. Z boolean
2. B byte
3. C char
4. D double
5. F float
6. I short
7. J long
8. L object
9. S short
10. V void
11. Lfully-qualified-class;fully-qualified-class
12. [type type[]
13. <init> constructor
Metod imzaları
(Param1;Param2)ReturnType
şeklinde yazılır.

11. maddede string,object[] parametreleri için şöyle yaparız
Ljava/lang/String;[Ljava/lang/Object;
Örnek
Şöyle yaparız.
jclass clz = env->FindClass("class/path/ListDataClass");
jmethodID mid = env->GetMethodID(clz, "getData", "([Lclass/path/ListDataClass;)V");
Örnek
Elimizde şu kod olsun.
map<string, string> mMap;
Bu nesneyi Java HashMap nesnesine çevirmek için şöyle yaparız.
env->PushLocalFrame(256); // fix for local references

jclass hashMapClass= env->FindClass(env, "java/util/HashMap");
jmethodID hashMapInit = env->GetMethodID(env, hashMapClass, "<init>", "(I)V");
jobject hashMapObj = env->NewObject(env, hashMapClass, hashMapInit, mMap.size());
jmethodID hashMapOut = env->GetMethodID(env, hashMapClass, "put",
            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

for (auto it : mMap)
{
    env->CallObjectMethod(env, hashMap, put,
         env->NewStringUTF(it->first.c_str()),
         env->NewStringUTF(it->second.c_str()));
}

env->PopLocalFrame(hashMap);
GetObjectArrayElement metodu
Java kodu şöyle olsun.
String[] args = ...;
new JNItest2().helloworld(args);
C kodunda şöyle yaparız.
JNIEXPORT void JNICALL
Java_JNItest2_helloworld(JNIEnv *env,jobject object, jobjectArray args)
{
 
  int i = ...
  jstring string = (jstring) env->GetObjectArrayElement(args, i);
  ...
}
GetObjectClass metodu
Şöyle yaparız.
jobject runnable = ...;
jclass cls = env->GetObjectClass( runnable);
GetStaticMethodID metoud
C kodundan Java kodunu çağırırken, FindClass ile bulunan Java nesnesinin static metodunu bulmak için kullanılır.
GetStringChars metodu
İmzası şöyle.
// Returns a pointer to the array of Unicode characters of the string. 
// This pointer is valid until ReleaseStringchars() is called.
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
GetStringLength metodu
jstring'in uzunluğunu verir. C kodunda şöyle yaparız.
jstring str =...;
int slength = env->GetStringLength(str);
GetStringUTFChars metodu
jstring'in karakterlerini döner. İmzası şöyle
// Returns a pointer to an array of bytes representing the string 
// in modified UTF-8 encoding. This array is valid until it is released 
// by ReleaseStringUTFChars().
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
C kodunda şöyle yaparız.
jstring str = ...;
char *jchars = (char *)env->GetStringUTFChars(str,NULL);
Şöyle yaparız.
std::string jstring2string(JNIEnv *env, jstring jStr) {
  if (!jStr)
    return "";

  std::vector<char> charsCode;
  const jchar *chars = env->GetStringChars(jStr, NULL);
  jsize len = env->GetStringLength(jStr);
  jsize i;

  for( i=0;i<len; i++){
    int code = (int)chars[i];
    charsCode.push_back( code );
  }
  env->ReleaseStringChars(jStr, chars);

  return  std::string(charsCode.begin(), charsCode.end());
}
NewIntArray metodu
Şöyle yaparız.
jint count = ...;
jintArray arr = env->NewIntArray (count);
ReleaseStringChars metodu
Şöyle yaparız.
std::string jstring2string(JNIEnv *env, jstring jStr) {
  if (!jStr)
    return "";

  std::vector<char> charsCode;
  const jchar *chars = env->GetStringChars(jStr, NULL);
  ...
  env->ReleaseStringChars(jStr, chars);

  return  std::string(charsCode.begin(), charsCode.end());
}