Roe*_*zen 5 java tomcat classloader
当我想将一种类型转换为另一种类型时,我得到以下异常.
java.lang.ClassCastException: org.paston.certification.data.impl.BRL6000
cannot be cast to org.paston.certification.data.Certification
Run Code Online (Sandbox Code Playgroud)
BRL6000扩展了认证.因此,根据我的理解,我应该能够将BRL6000类型的对象转换为认证类型.
这是发生异常的代码.
Object certification = ch.getCertificationData(process, version);
Certification c = (Certification)certification;
Run Code Online (Sandbox Code Playgroud)
部署
该应用程序从Eclipse部署到Tomcat 7服务器.我的应用程序使用Tomcat环境中的一些JAR(例如Bonita_Server.jar).
我的应用程序(在Eclipse中)是一个动态Web项目,它引用了包含类Certification和的其他项目(Certificationnl)BRL6000.当我将应用程序部署到Tomcat时,Project Certificationnl被添加到webproject的WAR中.
类
BRL6000级
package org.paston.certification.data.impl;
import org.paston.certification.data.Certification;
import org.paston.certification.data.CertificationStep;
public class BRL6000 extends Certification{
/**
*
*/
public static final long serialVersionUID = -8215555386637513536L;
public static final String processName = "BRL6000";
}
Run Code Online (Sandbox Code Playgroud)
认证课程
package org.paston.certification.data;
import java.util.ArrayList;
import java.util.List;
import org.ow2.bonita.facade.runtime.impl.AttachmentInstanceImpl;
public class Certification implements java.io.Serializable{
public enum Section{
ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN
}
/**
* SerializationVersionUID
*/
private static final long serialVersionUID = -5158236308772958478L;
}
Run Code Online (Sandbox Code Playgroud)
getCertificationData
public Object getCertificationData(String process, String version) {
if (loginContext == null)
login();
System.out.println("Process: "+ process + " Version: "+ version);
ProcessDefinitionUUID pdu = new ProcessDefinitionUUID(process, version);
QueryRuntimeAPI queryRuntimeAPI = AccessorUtil
.getQueryRuntimeAPI();
try {
Set<ProcessInstance> processInstances = queryRuntimeAPI
.getProcessInstances(pdu);
if (processInstances.size() != 1)
System.out.println("Best number of instances is 1. Found: "
+ processInstances.size());
for (ProcessInstance processInstance : processInstances) {
Map<String, Object> variables = processInstance
.getLastKnownVariableValues();
if (((Boolean) variables.get("active")) == true) {
return variables.get("certification");
}
}
} catch (ProcessNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
使用代码作为Servlet进行更新
package org.paston.certification.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.paston.certification.CertificationHandler;
import org.paston.certification.data.Certification;
import org.paston.certification.data.CertificationI;
/**
* Servlet implementation class SomeServlet
*/
public class SomeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SomeServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
CertificationHandler ch = new CertificationHandler();
String process = request.getParameter("p");
String version = request.getParameter("v");
Object certification = ch.getCertificationData(process, version);
Class<?> clazz = certification.getClass();
while (clazz != null) {
System.out.println(clazz.getName());
clazz = clazz.getSuperclass();
}
Class c1 = certification.getClass().getSuperclass();
Class c2 = Certification.class;
System.out.println("c1 is " + c1 + ", c2 is " + c2);
System.out.println("c1 == c2 is " + (c1 == c2));
System.out.println("c1.equals(c2) is " + c1.equals(c2));
System.out.println("c1.getName().equals(c2.getName()) is "
+ c1.getName().equals(c2.getName()));
System.out.println("c1.getClassLoader() == c2.getClassLoader() is "
+ (c1.getClassLoader() == c2.getClassLoader()));
CertificationI c = (CertificationI) certification;
PrintWriter out = response.getWriter();
out.println("Hello World");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
Run Code Online (Sandbox Code Playgroud)
Servlet的控制台输出:
进程:BRL6000版本:1.0 org.paston.certification.data.impl.BRL6000 org.paston.certification.data.Certification java.lang.Object c1是类org.paston.certification.data.Certification,c2是类org.paston .certification.data.Certification c1 == c2为false c1.equals(c2)为false c1.getName().equals(c2.getName())为true c1.getClassLoader()== c2.getClassLoader()为false
还有一个问题可能暗示这个问题.每隔10秒我在控制台中看到以下异常:
May 07, 2013 2:09:45 PM org.apache.catalina.loader.WebappClassLoader loadClass
INFO: Illegal access: this web application instance has been stopped already. Could not load org.ow2.bonita.runtime.tx.StandardTransaction. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1566)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at org.ow2.bonita.util.ReflectUtil.loadClass(ReflectUtil.java:68)
at org.ow2.bonita.env.descriptor.ObjectDescriptor.construct(ObjectDescriptor.java:195)
at org.ow2.bonita.env.WireContext.construct(WireContext.java:521)
at org.ow2.bonita.env.WireContext.create(WireContext.java:498)
at org.ow2.bonita.env.WireContext.create(WireContext.java:484)
at org.ow2.bonita.env.WireContext.get(WireContext.java:456)
at org.ow2.bonita.env.WireContext.get(WireContext.java:343)
at org.ow2.bonita.env.WireContext.get(WireContext.java:746)
at org.ow2.bonita.env.BasicEnvironment.get(BasicEnvironment.java:151)
at org.ow2.bonita.env.BasicEnvironment.get(BasicEnvironment.java:142)
at org.ow2.bonita.util.EnvTool.getEnvClass(EnvTool.java:175)
at org.ow2.bonita.util.EnvTool.getTransaction(EnvTool.java:84)
at org.ow2.bonita.runtime.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:42)
at org.ow2.bonita.services.impl.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)
at org.ow2.bonita.services.impl.RetryInterceptor.execute(RetryInterceptor.java:59)
at org.ow2.bonita.runtime.event.EventExecutorThread.run(EventExecutorThread.java:61)
Run Code Online (Sandbox Code Playgroud)
更新2
我开始明白这个问题了.所述Bonitaserver( AccessorUtil)不加载该认证对象为好.它在某处加载了Certification.jar1620768823629427276.tmpBonitaserver在将进程上传到服务器时创建的类.
此外,我发现了一个类ReflectUtil(链接),它可能用于加载这些类.
我试图在使用doGet的两个本(servlet的)开始加载类作为ClassLoader的AccessorUtil.两者都有相同的旧结果.
ArrayList<String> classesNames = new ArrayList<String>();
classesNames.add("org.paston.certification.data.Certification");
classesNames.add("org.paston.certification.data.CertificationI");
classesNames.add("org.paston.certification.data.impl.BRL6000");
ClassLoader cl = this.getClass().getClassLoader();
Class<?>[] classes = ReflectUtil.loadClasses(cl, classesNames);
Run Code Online (Sandbox Code Playgroud)
更新3
@GaborSch提出的以下代码的结果.我用它的代码:
System.out.println("--- Test ClassLoader certification object---");
ClassLoader cl1 = certification.getClass().getSuperclass().getClassLoader();
while (cl1 != null) {
System.out.println(cl1.getClass().getCanonicalName() + " " + cl1.hashCode() + " " + cl1);
cl1 = cl1.getParent();
}
System.out.println("--- Test ClassLoader Certification class---");
ClassLoader cl2 = Certification.class.getClassLoader();
while (cl2 != null) {
System.out.println(cl2.getClass().getCanonicalName() + " " + cl2.hashCode() + " " + cl2);
cl2 = cl2.getParent();
}
Run Code Online (Sandbox Code Playgroud)
代码结果:
--- Test ClassLoader certification object---
org.ow2.bonita.runtime.ProcessClassLoader 451656
org.ow2.bonita.runtime.ProcessClassLoader@6e448
org.ow2.bonita.runtime.VirtualCommonClassloader 1182018350
org.ow2.bonita.runtime.VirtualCommonClassloader@46742b2e
org.apache.catalina.loader.StandardClassLoader 318536939
org.apache.catalina.loader.StandardClassLoader@12fc7ceb
sun.misc.Launcher.AppClassLoader 1667514408
sun.misc.Launcher$AppClassLoader@63644028
sun.misc.Launcher.ExtClassLoader 1253061906
sun.misc.Launcher$ExtClassLoader@4ab03512
--- Test ClassLoader Certification class---
org.apache.catalina.loader.WebappClassLoader 2136824254
WebappClassLoader context: /Certification delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@12fc7ceb
org.apache.catalina.loader.StandardClassLoader 318536939
org.apache.catalina.loader.StandardClassLoader@12fc7ceb
sun.misc.Launcher.AppClassLoader 1667514408
sun.misc.Launcher$AppClassLoader@63644028
sun.misc.Launcher.ExtClassLoader 1253061906
sun.misc.Launcher$ExtClassLoader@4ab03512
Run Code Online (Sandbox Code Playgroud)
我怀疑问题的根源在于运行时环境.
您的Certification数据最终来自AccessorUtil.getQueryRuntimeAPI(),这是Tomcat运行的静态方法,因此来自它的所有对象实例都可能由Tomcat类加载器加载.
如果您在Tomcat下复制jar文件,它将使用自己的类加载器加载它.您的eclipse运行代码虽然使用了不同的类加载器,但如果它们没有加载此类的共同祖先类加载器,Certification则它们将被视为不同的类.
我建议检查你的运行时类路径,从你的Tomcat中删除libs,或者(最坏的情况)在Tomcat中运行你的代码(例如在同一个应用程序中作为Servlet).
更新:
基于项目部署描述我相信
AccessorUtil类是由一个共同的类加载器加载Certification实例填充CertificationnlAccessorUtil类访问这些对象,但无法从Eclipse代码访问类定义.在JVM级别从外部访问Tomcat定义的对象是个坏主意.将您的代码放入同一容器中,或使用正确定义的接口(例如Web服务).
如果您想继续使用当前的项目设置,您还可以使用放入公共类加载器(旁边AccessorUtil)的接口,并转换为接口.
更新2:
要检查类加载器层次结构,请执行如下代码:
Class c1 = certification.getClass().getSuperclass().getClassLoader();
while (c1 != null) {
System.out.println(c1.getClass().getCanonicalName() + " " + c1.hashCode() + " " + c1);
c1 = c1.getParent();
}
Class c2 = Certification.class.getClassLoader();
while (c2 != null) {
System.out.println(c2.getClass().getCanonicalName() + " " + c2.hashCode() + " " + c2);
c2 = c2.getParent();
}
Run Code Online (Sandbox Code Playgroud)
您可以通过比较堆栈找到共同的祖先.最好的方法仍然是调试.
更新3:
您可以看到您的常用类加载器org.apache.catalina.loader.StandardClassLoader.最重要的是
org.apache.catalina.loader.WebappClassLoader适用于您的webapp(这是您要投射到的地方)org.ow2.bonita.runtime.VirtualCommonClassloader并且org.ow2.bonita.runtime.ProcessClassLoader存在于对象来自的地方(这是它们被实例化的地方)似乎Bonita正在使用某种类加载机制.
解决方案是您使StandardClassloader(或任何其他类加载器)加载您的类.由于Certification(因此BRL6000)都依赖于博尼塔类,你必须把Bonita_Server.jar到认可.查看Tomcat Classloader HOWTO,它可能会为您提供更多洞察力.
更新4:
要进行我的评论中推荐的序列化/反序列化,您可以使用以下代码:
Certification certification = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ch.getCertificationData(process, version));
oos.flush();
certification = (Certification) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();
} catch (IOException | ClassNotFoundException ex) {
}
Run Code Online (Sandbox Code Playgroud)
请注意,(Certification)强制转换为当前加载的类.
更新5:
最终的解决方案不是使用直接的Java类级别访问,而是使用适当的API来执行相同的操作.
| 归档时间: |
|
| 查看次数: |
1332 次 |
| 最近记录: |