gpt4 book ai didi

java - 无法通过类型转换为类型

转载 作者:搜寻专家 更新时间:2023-10-31 19:28:51 28 4
gpt4 key购买 nike

当我想将一种类型转换为另一种类型时出现以下异常。

java.lang.ClassCastException: org.paston.certification.data.impl.BRL6000 
cannot be cast to org.paston.certification.data.Certification

BRL6000 扩展了认证。因此,据我所知,我应该能够将 BRL6000 类型的对象转换为 Certification 类型。

这是发生异常的代码。

Object certification = ch.getCertificationData(process, version);
Certification c = (Certification)certification;

部署

应用程序从 Eclipse 部署到 Tomcat 7 服务器。我的应用程序使用了一些来自 Tomcat 环境的 JAR(例如 Bonita_Server.jar)。

我的应用程序(在 Eclipse 中)是一个动态 Web 项目,它引用另一个项目 (Certificationnl),其中包含类 CertificationBRL6000。当我将应用程序部署到 Tomcat 时,项目 Certificationnl 被添加到 web 项目的 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";

}

认证等级

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;


}

获取认证数据

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;
}

使用代码作为 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
}

}

Servlet 的控制台输出:

Process: BRL6000 Version: 1.0 org.paston.certification.data.impl.BRL6000 org.paston.certification.data.Certification java.lang.Object c1 is class org.paston.certification.data.Certification, c2 is class org.paston.certification.data.Certification c1 == c2 is false c1.equals(c2) is false c1.getName().equals(c2.getName()) is true c1.getClassLoader() == c2.getClassLoader() is 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)

更新 2

我开始更好地理解这个问题。 Bonitaserver ( AccessorUtil ) 确实 也加载 Certification 对象。它在某个地方从 Certification.jar1620768823629427276.tmp 加载类,Bonitaserver 在进程上传到服务器时创建了这些类。

此外,我发现了一个类 ReflectUtil ( link ),它可能用于加载这些类。

我尝试的是在 doGet 的开头为这个(servlet)加载类作为 AccessorUtilClassLoader。两者都具有相同的旧结果。

    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);

更新 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();
}

代码结果:

--- 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

最佳答案

我怀疑问题的根源在于运行环境。

你的Certification数据最终来自AccessorUtil.getQueryRuntimeAPI(),这是Tomcat运行的一个静态方法,所以来自它的所有对象实例都有可能被加载由 Tomcat 类加载器。

如果你把jar文件复制到Tomcat下,它会用自己的类加载器加载它。您的 eclipse 运行代码虽然使用不同的类加载器,并且如果它们没有加载此 Certification 类的共同祖先类加载器,它们将被视为不同的类

我建议检查您的运行时类路径,从您的 Tomcat 中删除库,或者(最坏的情况)在 Tomcat 中运行您的代码(例如,作为同一应用程序中的 Servlet)。

更新:

根据项目部署描述我认为

  • AccessorUtil 类由通用类加载器加载
  • 里面的列表由来自 Certificationnl 类的 Certification 实例填充,来自您的 Tomcat 部署
  • 您可以通过 AccessorUtil 类访问这些对象,但无法从 Eclipse 代码访问类定义。

在 JVM 级别从外部访问 Tomcat 定义的对象不是一个好主意。要么将您的代码放入同一个容器中,要么使用正确定义的接口(interface)(例如 Web 服务)。

如果您想保留当前的项目设置,您还可以使用放入通用类加载器(AccessorUtil 旁边)的接口(interface),然后转换为该接口(interface)。

更新 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();
}

你可以通过比较堆栈来找到共同的祖先。继续进行的最佳方式仍然是调试

更新 3:

可见你常用的类加载器是org.apache.catalina.loader.StandardClassLoader。最重要的是

  • org.apache.catalina.loader.WebappClassLoader 存在于您的网络应用中(这是您要转换到的地方)
  • org.ow2.bonita.runtime.VirtualCommonClassloaderorg.ow2.bonita.runtime.ProcessClassLoader 出现在对象来自的地方(那是 它们的地方'重新实例化)

Bonita 似乎使用了某种类加载机制。

解决方案是让StandardClassloader(或任何其他类加载器)加载您的类。由于 Certification(因此 BRL6000)依赖于 Bonita 类,您必须将 Bonita_Server.jar 放入 endorsed。查看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) {
}

请注意,(Certification) 转换为当前加载的类。

更新 5:

最终的解决方案是不使用直接的 Java 类级访问,而是使用适当的 API 来实现相同的目的。

关于java - 无法通过类型转换为类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16400279/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com