jpa使用demo
c++ 中的结构体转换为对应的java类
将c++的结构体,函数方法转化为java对应的java,对于复杂的c++代码如果手动写,可能要写到天荒地老。这里采用了jnaerator 的工具包,进行转化。如果c++代码是自己写的,比较简单的话可以自己写对应的java文件。
使用方式:
参数说明:
-runtime JNA
指定目标运行库为JNA,
-runtime 可选的值有(区分大小写):
JNA
JNAerator (based on JNA)
-mode Maven
指定输出模式为Maven
-mode可选的值(区分大小写):
Jar : JAR 生成jar包,可以使用-jar指定生成的jar包文件名
StandaloneJar : 生成包含所有依赖库的jar ,可以使用-jar指定生成的jar包文件名
Directory : 生成代码到文件夹
Maven : 生成maven格式的项目(pom.xml)
AutoGeneratedMaven : 生成maven格式的项目(pom.xml),执行mave install 自动编译生成jar包,不生成源码
-mavenGroupId net.gdface
指定 maven项目的 groupId
-mavenArtifactId cassdk_jna
指定 maven项目的 artifactId
-o jna_code
指定输出文件夹 jna_code
-package net.gdface.jna
指定生成java代码的包名。如果不指定,则默认包名为 library name
-f
生成代码时强制覆盖已经存在的文件
-library THFaceImage -library THFeature
指定后面的动态库的名称(library name),在这里为”THFeature.dll”,如果不指定则library name 为 头文件名称:‘THFeature_i’,
NOTE:-library就是个状态参数,只对其后面的文件名参数有效,所以这里用两次-library分别为THFeature_i.h和THFeature_i.h指定了不同的动态库名称
bin\THFeature.dll include\THFeature_i.h bin\THFeature.dll include\THFeature_i.h
指定要生成代码的动态库和对应头文件,前后顺序无关,可以不提供动态库文件名称,只需要.h文件就可以生成JNA代码
c++ demo
本人于c++属于未入门级别,c++代码是在网上找的,如下
/*
* =====================================================================================
*
* Filename: TestDll1.cpp
*
* =====================================================================================
*/
#include <string.h>
#include <wchar.h>
#define MYLIBAPI extern "C"
MYLIBAPI void say(wchar_t *pValue);
struct UserStruct{
long id;
wchar_t *name;
int age;
};
MYLIBAPI void sayUser(UserStruct *pUserStruct);
struct CompanyStruct{
long id;
wchar_t *name;
UserStruct users[100];
int count;
};
struct CompanyStruct2{
long id;
wchar_t *name;
UserStruct *users[100];
int count;
};
#pragma pack(1)
struct NestedStruct{
char pwd[16];
char key[16];
char padding[113];
};
struct SimpleStruct{
NestedStruct nested;
int a;
unsigned char b;
int c;
int d;
char name[100];
};
#pragma pack()
MYLIBAPI void sayCompany(CompanyStruct* pCompanyStruct);
MYLIBAPI void sayCompany2(CompanyStruct2 *pCompanyStruct);
MYLIBAPI void getCompany(CompanyStruct *pCompanyStruct);
MYLIBAPI void getSimpleStruct(SimpleStruct *simp);
MYLIBAPI void saySimpleStruct(SimpleStruct *simp);
#include <iostream>
void say(wchar_t *pValue){
std::wcout<<L"上帝说: "<<pValue<<std::endl;
}
void sayUser(UserStruct *pUserStruct){
std::wcout<<L"ID: "<<pUserStruct->id<<std::endl;
std::wcout<<L"姓名: "<<pUserStruct->name<<std::endl;
std::wcout<<L"年龄: "<<pUserStruct->age<<std::endl;
}
void sayCompany(CompanyStruct *pCompanyStruct){
std::wcout<<L"ID: "<<pCompanyStruct->id<<std::endl;
std::wcout<<L"公司名称: "<<pCompanyStruct->name<<std::endl;
std::wcout<<L"员工总数: "<<pCompanyStruct->count<<std::endl;
for (int i = 0; i < pCompanyStruct->count; i++){
sayUser(&pCompanyStruct->users[i]);
}
}
void sayCompany2(CompanyStruct2 *pCompanyStruct){
std::wcout<<L"ID: "<<pCompanyStruct->id<<std::endl;
std::wcout<<L"公司名称: "<<pCompanyStruct->name<<std::endl;
std::wcout<<L"员工总数: "<<pCompanyStruct->count<<std::endl;
for (int i = 0; i < pCompanyStruct->count; i++){
sayUser(pCompanyStruct->users[i]);
}
}
void getCompany(CompanyStruct *pCompanyStruct){
pCompanyStruct->count = 1;
wcscpy(pCompanyStruct->name, L"Out Name");
pCompanyStruct->id = 13;
}
void getSimpleStruct(SimpleStruct *simp){
simp->a = 1;
simp->b = 2;
simp->c = 3;
simp->d = 4;
memset(simp->name, 0, sizeof(simp->name));
strcpy(simp->name, "test");
memset(&simp->nested, 0, sizeof(NestedStruct));
strcpy(simp->nested.pwd, "pwd");
strcpy(simp->nested.key, "key");
}
void saySimpleStruct(SimpleStruct *simp){
std::wcout<<L"simp->a = "<<simp->a<<std::endl;
std::wcout<<L"simp->b = "<<simp->b<<std::endl;
std::wcout<<L"simp->c = "<<simp->c<<std::endl;
std::wcout<<L"simp->d = "<<simp->d<<std::endl;
std::wcout<<L"simp->name = "<<simp->name<<std::endl;
std::wcout<<L"simp->nested.pwd ="<<simp->nested.pwd<<std::endl;
std::wcout<<L"simp->nested.key ="<<simp->nested.key<<std::endl;
}
c++文件生成的java代码:
备注: 这个文件不是使用jnaerator 工具生成的,工作中实际生成过,亲测可用,涉及到公司机密,源文件不便放出。这个cpp文件由于没有h文件,所以没生成,java文件为网上找到的。
//package com.sun.jna;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Structure;
import com.sun.jna.WString;
public class TestDll1Service {
/*
* 定义一个类,模拟C语言的结构
*
*/
public static class UserStruct extends Structure{
public static class ByReference extends UserStruct implements Structure.ByReference {
public ByReference() {}
//public ByReference(Pointer p){ super(p);}
}
public static class ByValue extends UserStruct implements Structure.ByValue {
public ByValue() {}
//public ByValue(Pointer p) { super(p);}
}
public NativeLong id;
public WString name;
public int age;
// 字段顺序与SO中结构体声明一致
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"id", "name", "age"
});
}
}
public static class CompanyStruct extends Structure{
public static class ByReference extends CompanyStruct implements Structure.ByReference {
public ByReference() {}
//public ByReference(Pointer p){ super(p);}
}
public static class ByValue extends CompanyStruct implements Structure.ByValue {
public ByValue() {}
//public ByValue(Pointer p) { super(p);}
}
public NativeLong id;
public WString name;
// 嵌套的结构体数组,下面三种声明都可以,注意每种声明的赋值方式
// Declare 1
// public UserStruct[] users = (UserStruct[])new UserStruct().toArray(100);
// Declare 2
// public UserStruct.ByValue[] users = new UserStruct.ByValue[100];
// Declare 3
public UserStruct[] users = new UserStruct[100];
public int count;
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"id", "name", "users", "count"
});
}
}
public static class CompanyStruct2 extends Structure{
public static class ByReference extends CompanyStruct2 implements Structure.ByReference {
public ByReference() {}
//public ByReference(Pointer p){ super(p);}
}
public static class ByValue extends CompanyStruct2 implements Structure.ByValue {
public ByValue() {}
//public ByReference(Pointer p){ super(p);}
}
public NativeLong id;
public WString name;
// 嵌套的结构体指针数组
public UserStruct.ByReference[] users=new UserStruct.ByReference[100];
public int count;
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"id", "name", "users", "count"
});
}
}
public static class NestedStruct extends Structure{
public static class ByValue extends NestedStruct implements Structure.ByValue{}
// 声明内存对齐方式,与SO中声明的结构体对齐保持一致
public NestedStruct() {super(ALIGN_NONE);}
// 注意C/C++中的char 对应java中的byte,其它类型之间的映射请参考官方文档
public byte pwd[] = new byte[16];
public byte key[] = new byte[16];
public byte padding[] = new byte[113];
protected List getFieldOrder(){
return Arrays.asList(new String[]{
"pwd", "key", "padding"});
}
}
public static class SimpleStruct extends Structure{
public static class ByReference extends SimpleStruct implements Structure.ByReference{}
public NestedStruct.ByValue nested = new NestedStruct.ByValue();
public int a;
public byte b;
public int c;
public int d;
public byte name[] = new byte[100];
public SimpleStruct(){super(ALIGN_NONE);};
protected List getFieldOrder(){
return Arrays.asList(new String[]{
"nested", "a", "b", "c", "d", "name"
});
}
}
public interface TestDll1 extends Library {
/**
* 当前路径是在项目下,而不是bin输出目录下。
*/
TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);
public void say(WString value);
public void sayUser(UserStruct.ByReference struct);
public void sayCompany(CompanyStruct.ByReference pCompanyStruct);
public void sayCompany2(CompanyStruct2.ByReference pCompanyStruct);
//public void getCompany(CompanyStruct.ByReference pCompanyStruct);
public void getSimpleStruct(SimpleStruct simp);
public void getSimpleStruct(SimpleStruct.ByReference simp);
public void saySimpleStruct(SimpleStruct simp);
}
public class TestClass{
int a;
int b;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TestDll1.INSTANCE.say(new WString("Hello World!"));
System.out.println("HHEEH中文");
UserStruct.ByReference userStruct = new UserStruct.ByReference();
userStruct.id = new NativeLong(100);
userStruct.age = 30;
userStruct.name = new WString("yifan");
TestDll1.INSTANCE.sayUser(userStruct);
System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAA");
CompanyStruct.ByReference companyStruct = new CompanyStruct.ByReference();
companyStruct.id = new NativeLong(1);
companyStruct.name = new WString("Google");
companyStruct.count = 9;
System.out.println("UserStruct size = " + userStruct.size());
System.out.println("CompanyStruct size = " + companyStruct.size());
for(int i = 0; i < companyStruct.count; i++){
/*
* Declare 1
companyStruct.users[i].id = new NativeLong(i);
companyStruct.users[i].name = new WString("yifan" + i);
companyStruct.users[i].age = 20 + i;
*/
/*
* Declare 2
UserStruct.ByValue user = new UserStruct.ByValue();
user.id = new NativeLong(i + 1);
user.name = new WString("yifan" + i);
user.age = 20 + i;
companyStruct.users[i] = user;
*/
/*
* Declare 3
*/
UserStruct user2 = new UserStruct();
user2.id = new NativeLong(i);
user2.name = new WString("yifan " + i);
user2.age = 20 + i;
companyStruct.users[i] = user2;
}
TestDll1.INSTANCE.sayCompany(companyStruct);
System.out.println("++++++++++++++");
CompanyStruct2.ByReference companyStruct2 = new CompanyStruct2.ByReference();
companyStruct2.id = new NativeLong(2);
companyStruct2.name = new WString("Yahoo");
companyStruct2.count = 10;
System.out.println("CompanyStruct2 size = " + companyStruct2.size());
for(int i = 0;i < companyStruct2.count; i++){
companyStruct2.users[i] = new UserStruct.ByReference();
companyStruct2.users[i].id = new NativeLong(i);
companyStruct2.users[i].name = new WString("Yahoo user" + i);
companyStruct2.users[i].age = 20 + i;
}
//companyStruct.write();
TestDll1.INSTANCE.sayCompany2(companyStruct2);
System.out.println("CCCCCCCCCCCCCCCCCCCCCCCCCCCC");
SimpleStruct.ByReference simple = new SimpleStruct.ByReference();
TestDll1.INSTANCE.getSimpleStruct(simple);
System.out.println("simple: size = " + simple.size());
System.out.println("simple: a = " + simple.a);
System.out.println("simple: b = " + simple.b);
System.out.println("simple: c = " + simple.c);
System.out.println("simple: d = " + simple.d);
System.out.println("simple: name = " + new String(simple.name));
System.out.println("simple: nested: pwd = " + new String(simple.nested.pwd));
System.out.println("simple: nested: key = " + new String(simple.nested.key));
System.out.println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
SimpleStruct simp2 = new SimpleStruct();
byte[] pwd = "simp2_pwd".getBytes();
byte[] key = "simp2_key".getBytes();
byte[] name = "simp2".getBytes();
simp2.a = 5;
simp2.b = 6;
simp2.c = 7;
simp2.d = 8;
//
// 对于已经声明大小的数组,使用下面数组赋值方式,
// 不要使用simp2.nested.pwd = "11".getBytes() 这种赋值方式
//
System.arraycopy(name, 0, simp2.name, 0, name.length);
System.arraycopy(pwd, 0, simp2.nested.pwd, 0, pwd.length);
System.arraycopy(key, 0, simp2.nested.key, 0, key.length);
TestDll1.INSTANCE.saySimpleStruct(simp2);
System.out.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
}
}
实际工作中是客户给的c++ 文件有c++头文件和 .so文件,涉及公司机密,就不上贴源码,这里只讲述整体流程,代码案例就使用简单demo。
根据c++ 代码生成so文件
g++ -fPIC -shared -o libhello.so hello.cpp
注意: 这里需要在c++环境。我是在linux下执行的,整理调用也是在linux下完成的。生成的
so文件要加上lib,因为加载系统文件时默认是寻找lib开头的文件。如: (Clibrary) Native.loadLibrary("hello",Clibrary.class); 系统其实是去寻找libhello文件,所以在生成so文件时,记得加上lib前缀。
写一个controller接口
将生成的java代码放在springboot项目中,在controller接口中调用java接口,进而调到对应c++接口
如下:
package cjc.cpp.test.mydemo;
import com.sun.jna.NativeLong;
import com.sun.jna.WString;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: mubai
* @Date: 2020-10-23 09:38
* @Description:
*/
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/demo")
public String demo() {
// TODO Auto-generated method stub
try {
TestDll1Service.TestDll1.INSTANCE.say(new WString("Hello World!"));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("HHEEH中文");
return "Hello World ! ";
}
@GetMapping("/test")
public String test() {
// return Service.instance.say();
return new Service().say();
}
public String say() {
return " hello";
}
}
将项目放在linux下执行
通过java -jar 将项目启动,调用http接口,进而调通了c++接口,展示效果如下:
注意:
这里需要特别注意,当时一致包找不到class文件,或无法加载到指定的文件。当时网上查了很多资料,so文件也放在了 /usr/lib 下了,直到看到一个博客说,要将so文件放在/usr/lib64 下面,因为我使用的机器是64为机器,jdk8,加载系统文件默认是到该目录下加载。
如有问题欢迎咨询,有错误的地方欢迎指正。