使用 dll 和 java jni4net 时出现 UnsatisfiedLinkError 异常
UnsatisfiedLinkError exception while working with dll and java jni4net
我一直致力于通过 jni4net 和核心 java 读取 c#(dll) 函数 java 我已经成功地从 dll 函数中获取了值,但现在我创建了一个 Dynamic Web 项目并尝试在 servlet 中使用相同的功能。但是现在只有dll文件加载成功,函数没有调用成功。以下是我到目前为止的尝试:
我的 Servlet:
public class LoginProcess extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Bridge.setVerbose(true);
Bridge.init();
Console.WriteLine("Hello .NET world!\n");
Bridge.LoadAndRegisterAssemblyFrom(new File("C:/Users/ashish.it/workspace/FinalJniWeb/WebContent/WEB-INF/lib/ADHelper.j4n.dll"));
} catch (IOException e) {
e.printStackTrace();
}
Enum output;
output=ADHelper.Login("user", "pass");
System.out.println(output);
}
}
我在核心 java 中做这个的唯一区别是我没有使用完整路径,而是我只使用 "lib/ADHelper.j4n.dll" 作为路径,但不知何故它在 servlet 中不起作用,所以我改变了它完成路径。反正dll文件加载成功了。
ADHelper.generated.cs
namespace ADHelper {
public partial class ADHelper_ {
methods.Add(global::net.sf.jni4net.jni.JNINativeMethod.Create(@__type, "Login", "Login2", "(Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;"));
private static global::net.sf.jni4net.utils.JniHandle Login2(global::System.IntPtr @__envp, global::net.sf.jni4net.utils.JniLocalHandle @__class, global::net.sf.jni4net.utils.JniLocalHandle UserName, global::net.sf.jni4net.utils.JniLocalHandle Password) {
// (Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;
// (LSystem/String;LSystem/String;)LADHelper/ADHelper+LoginResult;
global::net.sf.jni4net.jni.JNIEnv @__env = global::net.sf.jni4net.jni.JNIEnv.Wrap(@__envp);
global::net.sf.jni4net.utils.JniHandle @__return = default(global::net.sf.jni4net.utils.JniHandle);
try {
@__return = global::net.sf.jni4net.utils.Convertor.StrongC2Jp<global::ADHelper.ADHelper.LoginResult>(@__env, global::ADHelper.ADHelper.Login(global::net.sf.jni4net.utils.Convertor.StrongJ2CString(@__env, UserName), global::net.sf.jni4net.utils.Convertor.StrongJ2CString(@__env, Password)));
}catch (global::System.Exception __ex){@__env.ThrowExisting(__ex);}
return @__return;
}
}
当我 运行 proxygen 命令时,下划线与名称 ADHelper class 混合在一起。在 dll 文件中有两个 classes 命名为 ADHelper 和 ADHelper
函数 Login() 也更改为 Login2(),但我的 servlet 无法识别 Login2(),而 Login() 可以识别。
生成JavaclassADHelper.java
package adhelper;
@net.sf.jni4net.attributes.ClrType
public class ADHelper extends system.Object {
private static system.Type staticType;
protected ADHelper(net.sf.jni4net.inj.INJEnv __env, long __handle) {
super(__env, __handle);
}
@net.sf.jni4net.attributes.ClrConstructor("()V")
public ADHelper() {
super(((net.sf.jni4net.inj.INJEnv)(null)), 0);
adhelper.ADHelper.__ctorADHelper0(this);
}
@net.sf.jni4net.attributes.ClrMethod("(LSystem/String;LSystem/String;)LADHelper/ADHelper+LoginResult;")
public native static system.Enum Login(java.lang.String UserName, java.lang.String Password);
public static system.Type typeof() {
return adhelper.ADHelper.staticType;
}
private static void InitJNI(net.sf.jni4net.inj.INJEnv env, system.Type staticType) {
adhelper.ADHelper.staticType = staticType;
}
}
所有映射都是正确的,但我的登录函数给出了 unsatisfiedLinkError。感谢您的耐心阅读,请解决我的问题。
出现以下错误console:
*All Dll file loaded message*
Jun 3, 2015 10:56:39 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet LoginProcess threw exception
java.lang.UnsatisfiedLinkError: adhelper.ADHelper.Login(Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;
at adhelper.ADHelper.Login(Native Method)
at com.karvy.login.LoginProcess.doGet(LoginProcess.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:662)
也许您可以测试 class-loader 在不同上下文中从不同的 class-loader 加载您的文件。
我认为这是类加载器的问题,后来我禁止我的文件从同一个类加载器加载时就不是了。
进一步检查表明,我给出的路径是目录中文件的直接路径,而不是指向与 servlet 上下文范围内的文件相同的方向。为此,我必须创建 servlet context object
,然后调用 getResuorce
方法,以便我可以准备我的文件并准备好使用。
这是从 servlet 上下文范围获取文件的代码:
ServletContext context = getServletContext();
String realPath = context.getRealPath("/WEB-INF/lib/ADHelper.j4n.dll");
File file = new File(realPath);
感谢@surabhi-rai 的支持。我已经发布了这个 asnwer,如果将来有人遇到这个问题可以来这里。谢谢你,欢迎。 ☻
通过 servlet 上下文对象获取您的文件引用,然后对其调用 getResource 方法。
现在您指向的是不在 servlet 上下文范围内的本地目录。
我一直致力于通过 jni4net 和核心 java 读取 c#(dll) 函数 java 我已经成功地从 dll 函数中获取了值,但现在我创建了一个 Dynamic Web 项目并尝试在 servlet 中使用相同的功能。但是现在只有dll文件加载成功,函数没有调用成功。以下是我到目前为止的尝试:
我的 Servlet:
public class LoginProcess extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Bridge.setVerbose(true);
Bridge.init();
Console.WriteLine("Hello .NET world!\n");
Bridge.LoadAndRegisterAssemblyFrom(new File("C:/Users/ashish.it/workspace/FinalJniWeb/WebContent/WEB-INF/lib/ADHelper.j4n.dll"));
} catch (IOException e) {
e.printStackTrace();
}
Enum output;
output=ADHelper.Login("user", "pass");
System.out.println(output);
}
}
我在核心 java 中做这个的唯一区别是我没有使用完整路径,而是我只使用 "lib/ADHelper.j4n.dll" 作为路径,但不知何故它在 servlet 中不起作用,所以我改变了它完成路径。反正dll文件加载成功了。
ADHelper.generated.cs
namespace ADHelper {
public partial class ADHelper_ {
methods.Add(global::net.sf.jni4net.jni.JNINativeMethod.Create(@__type, "Login", "Login2", "(Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;"));
private static global::net.sf.jni4net.utils.JniHandle Login2(global::System.IntPtr @__envp, global::net.sf.jni4net.utils.JniLocalHandle @__class, global::net.sf.jni4net.utils.JniLocalHandle UserName, global::net.sf.jni4net.utils.JniLocalHandle Password) {
// (Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;
// (LSystem/String;LSystem/String;)LADHelper/ADHelper+LoginResult;
global::net.sf.jni4net.jni.JNIEnv @__env = global::net.sf.jni4net.jni.JNIEnv.Wrap(@__envp);
global::net.sf.jni4net.utils.JniHandle @__return = default(global::net.sf.jni4net.utils.JniHandle);
try {
@__return = global::net.sf.jni4net.utils.Convertor.StrongC2Jp<global::ADHelper.ADHelper.LoginResult>(@__env, global::ADHelper.ADHelper.Login(global::net.sf.jni4net.utils.Convertor.StrongJ2CString(@__env, UserName), global::net.sf.jni4net.utils.Convertor.StrongJ2CString(@__env, Password)));
}catch (global::System.Exception __ex){@__env.ThrowExisting(__ex);}
return @__return;
}
}
当我 运行 proxygen 命令时,下划线与名称 ADHelper class 混合在一起。在 dll 文件中有两个 classes 命名为 ADHelper 和 ADHelper
函数 Login() 也更改为 Login2(),但我的 servlet 无法识别 Login2(),而 Login() 可以识别。
生成JavaclassADHelper.java
package adhelper;
@net.sf.jni4net.attributes.ClrType
public class ADHelper extends system.Object {
private static system.Type staticType;
protected ADHelper(net.sf.jni4net.inj.INJEnv __env, long __handle) {
super(__env, __handle);
}
@net.sf.jni4net.attributes.ClrConstructor("()V")
public ADHelper() {
super(((net.sf.jni4net.inj.INJEnv)(null)), 0);
adhelper.ADHelper.__ctorADHelper0(this);
}
@net.sf.jni4net.attributes.ClrMethod("(LSystem/String;LSystem/String;)LADHelper/ADHelper+LoginResult;")
public native static system.Enum Login(java.lang.String UserName, java.lang.String Password);
public static system.Type typeof() {
return adhelper.ADHelper.staticType;
}
private static void InitJNI(net.sf.jni4net.inj.INJEnv env, system.Type staticType) {
adhelper.ADHelper.staticType = staticType;
}
}
所有映射都是正确的,但我的登录函数给出了 unsatisfiedLinkError。感谢您的耐心阅读,请解决我的问题。
出现以下错误console:
*All Dll file loaded message*
Jun 3, 2015 10:56:39 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet LoginProcess threw exception
java.lang.UnsatisfiedLinkError: adhelper.ADHelper.Login(Ljava/lang/String;Ljava/lang/String;)Lsystem/Enum;
at adhelper.ADHelper.Login(Native Method)
at com.karvy.login.LoginProcess.doGet(LoginProcess.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:662)
也许您可以测试 class-loader 在不同上下文中从不同的 class-loader 加载您的文件。
我认为这是类加载器的问题,后来我禁止我的文件从同一个类加载器加载时就不是了。
进一步检查表明,我给出的路径是目录中文件的直接路径,而不是指向与 servlet 上下文范围内的文件相同的方向。为此,我必须创建 servlet context object
,然后调用 getResuorce
方法,以便我可以准备我的文件并准备好使用。
这是从 servlet 上下文范围获取文件的代码:
ServletContext context = getServletContext();
String realPath = context.getRealPath("/WEB-INF/lib/ADHelper.j4n.dll");
File file = new File(realPath);
感谢@surabhi-rai 的支持。我已经发布了这个 asnwer,如果将来有人遇到这个问题可以来这里。谢谢你,欢迎。 ☻
通过 servlet 上下文对象获取您的文件引用,然后对其调用 getResource 方法。
现在您指向的是不在 servlet 上下文范围内的本地目录。