IT_Programming/Java

[펌] JNI - Package 안에서 JNI 사용하기 (JNI IN PACKAGE)

JJun ™ 2010. 9. 29. 15:45

-----------------------------------------------------------------------------------

                                                        출처: http://blog.naver.com/slaghter/5801897

-----------------------------------------------------------------------------------


 

▶ 문제

    JNI를 사용하는 자바의 클래스가 패키지형태로 되었을 경우


    즉, 코드가
                     package com.javapattern.jni;

                     import ...
                     publc class ...

    라고 되어 있을 경우 백날 해봐야 위의 exception이 난다.

위와 같은 문제가 발생을 할 경우 JNI에 대한 컴파일 방식이 달라져야 한다

 


▶ package 형태의 java class에서 JNI의 사용

보통의 JNI는 아래와 같은 특수한 format의 메소드가 사용이 됩니다.

 

Class이름이 TestJNI 라고 가정 하면

    public native void methodName();

인터페이스 선언과 비슷하게 생겼습니다..

위의 methodName에 해당하는 native function은 아래와 같은 형태의 header로 작성이 되게 됩니다.
   
    JNIEXPORT void JNICALL Java_클래스이름_메소드이름(arg);

변환해보면 header파일은

    JNIEXPORT void JNICALL Java_TestJNI_methodName(JNIEnv *, jobject);

이 됩니다.

위와 같은 헤더파일을 작성하기 위해서는 package형태의 JNI클래스를 compile 해야 합니다.

당근 원래의 클래스파일을 이미 컴파일된 상태여야 하고, 그런 후에 javah명령어를 써서 하게 됩니다.

즉,

javah com.javapattern.jni.JNITest

자 그러면 차례차례로 클래스를 작성하는 것부터 보도록 하면.....

아래와 같이 auth를 따는 클래스를 작성한다고 가정하면...


 package com.javapattern.util;
 public class AuthUtil {
       /** Native import */
       public static native String SetAuthenticationValC(
                String cmd, int version, int keyindex, String key1, String key2);
       public static native int    GetAuthenticationValC(
                String cmd, int version, int keyindex, String key1, String key2, long auth);
   static {
       System.out.println("Load");
       try{
               System.loadLibrary("Callxfsp");
       }catch(Exception e) {
               e.printStackTrace();
       }
       System.out.println("Load OK!");
   }
   public static String getAuth() {
        return SetAuthenticationValC("SO", 1, 6, "25", "45");
   }
 }



먼저 위의 클래스를 컴파일합니다. 소스의 위치는 compile root로부터 com/javapattern/util에 위치시킵니다.

그런 후에

    javac ./com/javapattern/util/AuthUtil.java

명령이 성공하게 되면 com/javapattern/util의 디렉토리에 AuthUtil.class가 생기게 됩니다.

그러면 현재 compile시킨 root디렉토리에서 다시 javah를 이용하여 해당 header파일을 작성하도록 합니다.

    javah com.javapattern.util.AuthUtil

위의 명령이 다시 성공하게 되면 header파일의 이름은 com_javapattern_util_AuthUtil.h파일로 생성됩니다.

그런 다음 C소스의 header에 위의 compile된 .h파일을 include시키도록 한 후 C를 작성하도록 합니다.


#include <stdio.h>
#include <memory.h>
#include "tubis_asi_wli_util_XFSPUtil.h"
#include "authutil.h"
/*
* Class:     Call.java
* Method:    SetAuthenticationValC
* Signature: ()I
*/
JNIEXPORT jstring JNICALL Java_com_javapatteru_util_AuthUtil_SetAuthenticationValC
 (JNIEnv *env, jclass clazz, jstring jcmd, jint jversion, jint jkeyindex, jstring jkey1, jstring jkey2)
{
    int iret = 0;
    char cret[10+1];
    char cmd[4096];
    char key1[4096];
    char key2[4096];
    unsigned long auth=0;
    // 이하 소스 주절주절
}


그런 다음에 C source를 컴파일하여 윈도우라면 dll, Unix라면 so파일을 컴파일하여 만들도록 합니다.
그리고 해당 dll이면 path에 so파일이면 LD_LIBRARY_PATH에 라이브러리 파일을 참조하도록 한 후
자바클래스로 호출하면 됩니다.


import com.javapattern.util.AuthUtil;
public class Call {
    public static void main(String [] args) {
        String str = AuthUtil.getAuth();
        System.out.println(str);
    }
}