2009-05-05 28 views
39

我有2个不同的Java项目,其中一个有2个类:dynamicbeans.DynamicBean2dynamic.ValidatorClassCastException当投射到相同的类

在其他项目中,我同时加载动态类,以及它们存储在一个Object

class Form { 
    Class beanClass; 
    Class validatorClass; 
    Validator validator; 
} 

然后我继续前进,用validatorClass.newInstance()创建Validator对象并将其存储在validator然后创建一个bean对象以及使用beanClass.newInstance()并将其添加到会话中。

portletRequest.setAttribute("DynamicBean2", bean); 

Form项目的生命周期,我叫validator.validate()从会话(我运行WebSphere Portal服务器)加载以前创建的bean对象。当我尝试将此对象转换回DynamicBean2时,它会因ClassCastException而失败。

当我拉对象回来了使用

faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces); 

会议并使用.getClass()我得到dynamicbeans.DynamicBean2检查类的吧。这是我想要将它转换为的类,但是当我尝试获取ClassCastException时。

为什么我得到这个?

回答

47

我并不完全遵循你对程序流的描述,但通常当你得到ClassCastExceptions时,你无法解释你已经用一个类加载器加载了类,然后尝试将它转换为由另一个类加载器加载的同一类。这是行不通的 - 它们在JVM中由两个不同的Class对象表示,并且转换将失败。

有一个article about classloading in WebSphere。我不能说它如何适用于您的应用程序,但有许多可能的解决方案。我至少可以想到:

  1. 手动更改上下文类加载器。要求你实际上可以得到一个适当的类加载器的引用,这在你的情况下可能是不可能的。

    Thread.currentThread().setContextClassloader(...); 
    
  2. 请确保该类由层次结构中较高级别的类加载器加载。

  3. 序列化和反序列化对象。 (呸!)

有可能是特定的情形更合适的方式虽然。

+3

我的猜测(我没有门户服务器的经验)是你正在加载类在不同的portlet,每个都有它自己的类加载器。然后将实例放入会话对象中,当您从错误的portlet(从中创建该portlet)中检索到该实例时,您就有异常。我猜(根据WAS经验),您需要将class放在类加载层次结构中较高的位置,以便它由两个portlet类加载器的父级加载。 – Robin 2009-05-05 20:51:50

+2

即2号细节。 – Robin 2009-05-05 20:52:55

+1

@waxwing这已经有一段时间了。但是,你介意阐述你所说的第一个可能的解决方案吗?我觉得我遇到的问题可以通过这个解决。提前致谢! – 2011-08-16 12:13:20

10

类对象被加载到不同的类加载器中,因此在每个类中创建的实例被视为“不兼容”。在使用许多不同类加载器并传递对象的环境中,这是一个常见问题。 Java EE和门户环境中可能会出现这些问题。

投射一个类的实例需要链接到被转换对象的类与当前线程上下文classloader加载的类相同。

0

当尝试使用Apache Commons Digester从XML创建对象列表时,我遇到了A2AClassCastException问题。

List<MyTemplate> templates = new ArrayList<MyTemplate>(); 
Digester digester = new Digester(); 
digester.addObjectCreate("/path/to/template", MyTemplate.class); 
digester.addSetNext("/path/to/template", "add"); 
// Set more rules... 
digester.parse(f); // f is a pre-defined File 

for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate 
    // Do stuff 
} 

如上所述,原因是蒸煮器不使用与程序其余部分相同的ClassLoader。我在JBoss中运行了这个程序,结果发现commons-digester.jar不在JBoss的lib目录中,而是在webapp的lib目录中。将jar复制到mywebapp/WEB-INF/lib中也解决了这个问题。另一种解决方案是对digester.setClassLoader(MyTemplate.class.getClassLoader())进行castion,但在这种情况下感觉像是一个相当丑陋的解决方案。

0

我在不同的机器上使用几个JBoss实例时遇到同样的问题。对我来说,这并不是偶然发现的。
在不同的计算机上部署了工件,其中两个声明了具有相同名称的类加载器。我更改了其中一个类加载器名称,并且所有工作都很好=>注意复制&粘贴!

为什么不抛出ClassCastException抛出涉及的类加载器? - 我认为这将是非常有用的信息。
有没有人知道未来会有这样的事情吗?需要检查20-30个文物的班级装载者是不是很愉快。或者有什么我在例外文本中错过了?

编辑:我编辑了META-INF/jboss-app.xml文件并更改了加载器的名称,这个想法是有一个唯一的名称。在工作中,我们使用artifact id(唯一)与maven({$ version})插入的版本相结合。
使用动态字段只是可选的,但有助于您部署同一应用程序的不同版本。

<jboss-app> 
    <loader-repository> 
    com.example:archive=unique-archive-name-{$version} 
    </loader-repository> 
</jboss-app> 

你可以在这里找到一些信息:https://community.jboss.org/wiki/ClassLoadingConfiguration

0

我有同样的问题,我终于找到了java.net上的一个解决方法:

复制所有文件org.eclipse.persistence jarglassfish4/glassfish/modulesWEB-INF/lib。然后进入您的glassfish-web.xml,并将class-delegate设置为false

为我工作!

0

我在野蛮EJB上有同样的问题,EJB正在返回一个对象列表并且有一个远程和一个本地接口。我错误地使用了Local接口,直到你试图在列表中转换对象的时候,工作得很好。

本地/远程接口:

public interface DocumentStoreService { 

    @javax.ejb.Remote 
    interface Remote extends DocumentStoreService { 
    } 

    @javax.ejb.Local 
    interface Local extends DocumentStoreService { 
    } 

的EJB豆:

@Stateless 
public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote { 

周围的EJB正确的春天包装:

<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean"> 
    <property name="jndiName" value="java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/> 
    <property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/> 
    <property name="resourceRef" value="true" /> 
</bean> 

注意$远程,您可以更改这到$本地,它会发现本地接口就好了,也执行没有任何问题的方法(从as相同容器上的单独应用程序),但如果您错误地使用本地接口,则模型对象不会封送并且来自不同的类加载器。

0

另一种选择:

发生在我身上了weblogic,但我想它可以在其他的服务器发生以及 - 如果你不(仅仅)“发布”,并为此您的某些类重新加载。相反,“清洁”,所有的类将重新加载在一起。

1

我对于来自另一个EJB的EJB查找有同样的问题。 我解决了将@Remote(MyInterface.class)添加到EJB类的配置

相关问题