java调用JNI总结

简介: java调用JNI总结

工作中需要用到java调用DES加密解密算法进行通信加密、MAC计算等,原来直接有C语言版的DES算法库可以用,但是java用的不熟,java的DES算法库没用过,就想到把C语言的DES算法库编译成DLL,然后通过java的JNI调用。


网上java调用jni的例子挺多,本以为挺简单的,但是实践了一下才知道,好多地方容易出错,这里总结一下容易出错的地方。


java调用JNI,按步骤,首先需要建一个类,声明本地方法。然后用javac编译这个类,最后用javah生成c语言的头文件并实现对应的*.c文件,并编译为动态库。把这个动态库放


在指定位置,如/bin目录下。在java中静态加载这个DLL。


以一个简单的例子说明:


package test;
public class TestDes {
   public native void SayHello(String name);
   public native void DesOperation(int[] pInOut,int[] pbKey,int cnt);
   public native int  MathDesMac(int[] pbuf,int len,int[] pbKey,int type);
   static
     {
        System.load(Class.class.getResource("/").getPath()+"test_TestDes.dll");
     //System.load("C:/Users/yang/A303workspc/testjni/bin/test/test_TestDes.dll");
     }
  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("java jni test:");
    System.out.println(Class.class.getResource("/").getPath());
    //System.out.println(System.getProperty("user.dir"));
    TestDes h=new TestDes();
    h.SayHello("nice to meet you!\r\n");
  }
}


常见的错误如:java.lang.UnsatisfiedLinkError,


javah -jni -classpath . test.TestDes


错误:无法访问 test.TestDes


javah -jni -classpath .  TestDes


错误:无法访问 TestDes


错误的类文件: .\TestDes.class


类文件包含错误的类: test.TestDes


原因是有些地方需要注意:


当调用javah命令生成c语言的头文件时,首先需要进入*java的源文件目录下,调用javac 把有本地方法的java类文件编译为*.class,然后用javah命令时,需要在正确的目录下调用,切换回src目录下调用javah -jni命令。注意,指定的类clss文件要带上包名。如 test.TestDes


如在yang@DESKTOP-LRJFD2R ~/a303workspc/testjni/src 目录下,调用javah -jni -classpath . test.TestDes


其中test是包的名字。



生成了test_TestDes.h的头文件。


文件内容如下:


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_TestDes */
#ifndef _Included_test_TestDes
#define _Included_test_TestDes
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_TestDes
 * Method:    SayHello
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_TestDes_SayHello
  (JNIEnv *, jobject, jstring);
/*
 * Class:     test_TestDes
 * Method:    DesOperation
 * Signature: ([I[II)V
 */
JNIEXPORT void JNICALL Java_test_TestDes_DesOperation
  (JNIEnv *, jobject, jintArray, jintArray, jint);
/*
 * Class:     test_TestDes
 * Method:    MathDesMac
 * Signature: ([II[II)I
 */
JNIEXPORT jint JNICALL Java_test_TestDes_MathDesMac
  (JNIEnv *, jobject, jintArray, jint, jintArray, jint);
#ifdef __cplusplus
}
#endif
#endif


接下来就需要用GCC把这些头文件中的函数给实现了。为了方便,直接把JNI.h和JNI_md.h文件和需要编译的C文件都放到src目录下。


同时把test_TestDes.h头文件中的include<jni.h>,尖括号换为“JNI.h”


GCC生成动态库,如下:gcc -std=c99  -Wl,--add-stdcall-alias  -shared



makefile文件:


########################################
#makefile
########################################
BINARY= test_TestDes
CC= gcc
LD= ld
CFLAGS= -std=c99  -Wl,--add-stdcall-alias 
#LDSCRIPT= -lws2_32
#LDFLAGS= -Llib
#OBJS=  helloworld.o
OBJS= curcalc_calc.o curcalc_crc.o curcalc_des.o curcalc_md5.o curcalc_oth.o  curcalc_sha1.o test_TestDes.o
#CFLAGS=-std=c99
.PHONY: clean
all:images
images: $(BINARY).dll
$(OBJS):%.o:%.c
$(CC) -c  $(CFLAGS) $< -o $@
%.dll: $(OBJS)
$(CC) $(CFLAGS) -shared -o $(BINARY).dll $(OBJS)
cp $(BINARY).dll ../bin
clean:
rm -f *.o


test_TestDes.c文件如下:


#include "test_TestDes.h"
#include <stdio.h>
#include <string.h>
#include "includes.h"
void JNICALL Java_test_TestDes_SayHello(JNIEnv * env, jobject obj, jstring str)
{
    jboolean  b ;
    char s[80];
    memset(s, 0, sizeof(s));
    strcpy(s ,(char*)(*env)->GetStringUTFChars(env,str, &b));
    printf("Hello, %s", s);
    (*env)->ReleaseStringUTFChars(env,str , NULL);
}
void JNICALL Java_test_TestDes_DesOperation(JNIEnv *env, jobject obj, jintArray data, jintArray key, jint t)
{
  jboolean  b ;
  jsize n1,n2;
  n1 = (*env)->GetArrayLength(env,data);
  n2 = (*env)->GetArrayLength(env,key);
  printf("len is %d\r\n",n1);
  if((n1 < 8) || (n2 < 8))
  {
    printf("lenth is not enough!");
    return;
  }
  jint jt1[n1];
  jint jt2[n2];
  unsigned char buf1[n1];
  unsigned char buf2[n2];
  //memcpy(s,(jint*)(*env)->GetIntArrayElements(env,data,&b),n);
  (*env)->GetIntArrayRegion(env,data,0,n1,jt1);
  for(int i=0;i < n1;i++)
  {
    buf1[i] = jt1[i];
  }
  printf("jt1 is %d %d %d %d\r\n",jt1[0],jt1[1],jt1[2],jt1[3]);
  printf("buf1 is %d %d %d %d\r\n",buf1[0],buf1[1],buf1[2],buf1[3]);
  //printf("len is %d\r\n",n2);
  //memcpy(s,(jint*)(*env)->GetIntArrayElements(env,data,&b),n);
  (*env)->GetIntArrayRegion(env,key,0,n2,jt2);
  for(int i=0;i < n2;i++)
  {
    buf2[i] = jt2[i];
  }
  CurCalc_DES_DesOperation( buf1, 0, 
                    buf2, 
                    SINGLE_DES_DECRYPTION | ZERO_CBC_IV, 
                    t ) ;
  printf("buf1 is %d %d %d %d\r\n",buf1[0],buf1[1],buf1[2],buf1[3]);
  (*env)->SetIntArrayRegion(env,data,0,8,jt1);
}
jint JNICALL Java_test_TestDes_MathDesMac(JNIEnv *env, jobject obj, jintArray data, jint len,jintArray key, jint type)
{
  return 0;
}


执行结果:


相关文章
|
5月前
|
Java API C++
Java JNI开发时常用数据类型与C++中数据类型转换
Java JNI开发时常用数据类型与C++中数据类型转换
213 0
|
2月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
68 11
|
2月前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
98 11
|
Java Linux 计算机视觉
全网首发:Could NOT find JNI (missing: JAVA_AWT_INCLUDE_PATH) 解决办法
全网首发:Could NOT find JNI (missing: JAVA_AWT_INCLUDE_PATH) 解决办法
344 0
|
3月前
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
29 0
|
3月前
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
34 0
|
3月前
|
算法 Java Linux
Intellij Java JNI 调用 C++
Intellij Java JNI 调用 C++
40 0
|
5月前
|
Java API Android开发
Java通过JNI调用C++的DLL库
Java通过JNI调用C++的DLL库
35 0
|
Java Android开发
Android JNI开发从0到1,java调C,C调Java,保姆级教程详解
Android JNI开发从0到1,java调C,C调Java,保姆级教程详解
88 1
|
6月前
|
Rust Java Linux
【一起学Rust | 进阶篇 | jni库】JNI实现Java与Rust进行交互
【一起学Rust | 进阶篇 | jni库】JNI实现Java与Rust进行交互
205 0