使用jpype调用Jar包中的实现方法
安装
pip install jpype1(注意要加后边这个1)
使用
基本流程如下:
- 使用jpype开启jvm
- 加载java类
- 调用java方法
- 关闭jvm
说明
我这里是在Python中使用Java的第三方抽象语法树包JavaParser(Python中的javalang实在太难用了),实现得到一个类文件中的所有的方法的功能
代码
Python代码:
import jpype
import os
import json
if __name__ == '__main__':
# 加载jar包
jarpath = os.path.join(os.path.abspath('.'),'D:/study/hdu-cs-learning/Paper/TD/BuildDataset/target/BuildDataset.jar')
# 获取jvm.dll的默认文件路径
jvmPath = jpype.getDefaultJVMPath()
# 开启虚拟机
jpype.startJVM(jvmPath, '-ea', '-Djava.class.path=%s' % (jarpath))
# 加载java类(参数名是java的长类名)
javaClass = jpype.JClass('scluis.API')
# 调用类中的方法
class_file_path = 'D:/study/TD/OpenSourceProject/JFreeChart/source/org/jfree/chart/fx/ChartViewer.java'
# 这里是调用scluis.API类的静态方法getMethods,如果调用实例方法,则需要先实例化java对象,即javaInstance = javaClass(),在使用实例调用
file_methods_str = javaClass.getMethods(class_file_path)
# 解析返回值,这里的返回值是json数组
methods_list = ""
if file_methods_str != "":
methods_list = json.loads(str(file_methods_str))
# 关闭虚拟机
jpype.shutdownJVM()
API.java:
package scluis;
import com.github.javaparser.ParseException;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Random;
public class API {
public static void main(String[] args) {
//main方法是为了测试Java代码即,getMethods,main方法不是必须的
String filePath="D:/study/OpenSourceProject/SQuirrel/app/src/net/sourceforge/squirrel_sql/client/gui/HelpViewerWindow.java";
String methods=getMethods(filePath);
System.out.println(methods);
}
public static String getMethods(String filePath){
String res="";
try {
Parser fileParser = new Parser();
res= fileParser.getFileMethods(filePath);
} catch (ParseException | IOException e) {
e.printStackTrace();
}
return res;
}
}
Parser.java(内含Java返回值格式)
package scluis;
import com.alibaba.fastjson.JSON;
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.printer.DotPrinter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class Parser {
private CompilationUnit m_CompilationUnit;
public CompilationUnit getParsedFile() {
return m_CompilationUnit;
}
public String getFileMethods(String filePath) throws ParseException, IOException {
String methodJson = "";
try {
m_CompilationUnit = StaticJavaParser.parse(new File(filePath));
FunctionVisitor functionVisitor = new FunctionVisitor();
functionVisitor.visit(m_CompilationUnit, null);
ArrayList<MethodDeclaration> nodes = functionVisitor.getMethodDeclarations();
ArrayList<Method> methodList = new ArrayList<>();
for (int i = 0; i < nodes.size(); i++) {
MethodDeclaration methodDeclaration = nodes.get(i);
//起止行
int startLine = methodDeclaration.getRange().get().begin.line;
int endLine = methodDeclaration.getRange().get().end.line;
//方法代码
String method = methodDeclaration.removeComment().toString();
Method m = new Method(startLine, endLine, method);
methodList.add(m);
}
methodJson = JSON.toJSONString(methodList);
} catch (Exception e) {
e.printStackTrace();
}
return methodJson;
}
}
jpype调用jar包“Class xx not found“问题
环境
- Java 1.8 (64位)
- Python 2.7.9 (32位)
- Jpype 0.5.4.2
- Pycharm
代码
import jpype
from jpype import *
# 该目录下有需要调用的jar包 pak.jar
jvmArg = "-Djava.ext.dirs=D:/1_Workspace/jpype_test/"
if not jpype.isJVMStarted():
jvmPath = jpype.getDefaultJVMPath()
jpype.startJVM(jvmPath,"-ea", jvmArg)
# pak.jar中包含类com.abc.EFG
jd = JClass("com.abc.EFG")
instance = jd()
print(instance.getName())
jpype.shutdownJVM()
问题
执行以上代码,报错如下。Class com.abc.EFG not found
检查点
1.在pak.jar包中有com.abc.EFG
类
2.EFG
依赖的jar包都在同级目录下
3.Jpype使用没有问题:调用System.out.println
可以打印
jprint = java.lang.System.out.println
jprint("xxx") #输出xxx
试着从环境上找原因,也许和Java版本有关。
首先查找pak.jar包的编译jdk版本
使用以上方法获得输出是 52,即对应java 1.8,与本机Java版本相符。
但是回头一想其实在Pycharm中并没有配置过Java的版本。
那么打印一下jvmPath
,获得的路径是C:\Program Files (x86)\Java\jre6\bin\client\jvm.dll
,=> 使用的是 jre1.6(32位)。
此时去Java1.8目录找,发现server
目录下有jvm.dll
,不是在client
目录。管他的,尝试直接指定存在的jvm.dll路径。
# ...
# jvmPath = jpype.getDefaultJVMPath()
jvmPath = r'D:\java\jdk1.8\jre\bin\server\jvm.dll'
jpype.startJVM(jvmPath,"-ea", jvmArg)
# ...
到这里也许有人的问题可以解决了,但我的情况是还是报错…
解决
最后装了jdk1.8 32位!!!,发现在client
目录下有jvm.dll
文件了
再次修改代码,执行通过。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。