Java 向同一类强制转换时的ClassCastException

Java 向同一类强制转换时的ClassCastException,java,reflection,classcastexception,websphere-portal,Java,Reflection,Classcastexception,Websphere Portal,我有两个不同的Java项目,其中一个有两个类:dynamicbeans.DynamicBean2和dynamic.Validator 在另一个项目中,我动态加载这两个类,并将它们存储在对象上 class Form { Class beanClass; Class validatorClass; Validator validator; } 然后,我继续使用validatorClass.newInstance()创建一个Validator对象,并将其存储在Validato

我有两个不同的Java项目,其中一个有两个类:
dynamicbeans.DynamicBean2
dynamic.Validator

在另一个项目中,我动态加载这两个类,并将它们存储在
对象上

class Form {
    Class beanClass;
    Class validatorClass;
    Validator validator;
}
然后,我继续使用
validatorClass.newInstance()
创建一个
Validator
对象,并将其存储在
Validator
上,然后使用
beanClass.newInstance()
创建一个bean对象,并将其添加到会话中

portletRequest.setAttribute("DynamicBean2", bean);
表单
项目的生命周期中,我调用
validator.validate()
,它从会话中加载先前创建的bean对象(我正在运行WebSpherePortal Server)。当我尝试将此对象强制转换回
DynamicBean2
时,由于ClassCastException而失败

当我使用

faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces);
并使用
.getClass()
检查它的类,我得到
dynamicbeans.DynamicBean2
。这是我想要将它转换到的类,但是当我尝试时,我得到了ClassCastException


有什么原因让我这么做吗?

我不太明白您对程序流的描述,但通常当您遇到ClassCastException时,您无法解释您使用一个类加载器加载了该类,然后尝试将其转换为另一个类加载器加载的同一个类。这将不起作用-它们由JVM中的两个不同类对象表示,转换将失败

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

  • 手动更改上下文类加载器。要求您可以实际获取对适当类加载器的引用,这在您的情况下可能是不可能的

    Thread.currentThread().setContextClassLoader(...);
    
  • 确保该类由层次结构中较高的类加载器加载

  • 序列化和反序列化对象。(恶心!)


  • 不过,对于您的特定情况,可能有一种更合适的方法。

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


    强制转换类实例要求链接到被强制转换对象的类与当前线程上下文类加载器加载的类相同。

    我在尝试使用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
    }
    
    List templates=new ArrayList();
    蒸煮器蒸煮器=新蒸煮器();
    digester.addObjectCreate(“/path/to/template”,MyTemplate.class);
    digester.addSetNext(“/path/to/template”,“add”);
    //设置更多规则。。。
    消化器。解析(f);//f是一个预定义的文件
    对于(MyTemplate t:templates){//ClassCastException:无法将mypackage.MyTemplate强制转换为mypackage.MyTemplate
    //做事
    }
    

    如上所述,原因是消化器没有使用与程序其余部分相同的类加载器。我在JBoss中运行了这个,结果发现commons-digester.jar不在JBoss的lib目录中,而是在webapp的lib目录中。将jar复制到mywebapp/WEB-INF/lib中也解决了这个问题。另一个解决方案是casll digester.setClassLoader(MyTemplate.class.getClassLoader()),但在这种情况下,这似乎是一个非常糟糕的解决方案。

    我在不同的机器上使用几个JBoss实例时遇到了同样的问题。糟糕的是,我之前没有偶然发现这篇文章。
    在不同的机器上部署了一些工件,其中两个用相同的名称声明了类加载器。我更改了一个类加载器名称,一切正常=>注意复制和粘贴

    为什么抛出的ClassCastException没有提到涉及的类装入器我认为这将是非常有用的信息
    有人知道将来会不会有类似的产品?需要检查20-30个工件的类装入器不是那么令人愉快。或者在例外文本中我遗漏了什么

    编辑:我编辑了META-INF/jboss-app.xml文件并更改了加载程序的名称,目的是要有一个唯一的名称。在工作中,我们将工件id(unique)与maven({$version})在构建过程中插入的版本结合使用
    使用动态字段只是可选的,但如果要部署同一应用程序的不同版本,则会有所帮助

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

    您可以在这里找到一些信息:

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

    将所有
    org.eclipse.persistence jar
    文件从
    glassfish4/glassfish/modules
    复制到
    WEB-INF/lib
    。然后进入
    glassfishweb.xml
    ,将
    类委托设置为
    false


    为我工作

    JAXB和JBoss与7.1有类似的问题。此处描述了问题和解决方案:。给出的例外是org.foo.bar.ValueSet不能转换为org.foo.bar.ValueSet

    我在wildfly EJB上遇到了同样的问题,EJB返回了一个对象列表,并且有一个远程和本地接口。我错误地使用了本地接口,直到您尝试在列表中强制转换对象时,它才正常工作

    本地/远程接口:

    public interface DocumentStoreService {
    
        @javax.ejb.Remote
        interface Remote extends DocumentStoreService {
        }
    
        @javax.ejb.Local
        interface Local extends DocumentStoreService {
        }
    
    EJB bean:

    @Stateless
    public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote {
    
    EJB周围正确的spring包装器:

    <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>
    
    
    
    注意$Remote,您可以将其更改为$Local,它会发现本地接口很好,并且也可以执行方法而不会出现任何问题(来自同一容器上的单独应用程序),但是如果您使用本地接口,则模型对象不会封送,而是来自不同的类装入器
    <dependencies>
        ...
        <module name="my.package"/>
    </dependencies>