转换为同一个类时出现 ClassCastException

发布于 2024-07-19 03:44:30 字数 1014 浏览 9 评论 0原文

我有 2 个不同的 Java 项目,其中一个有 2 个类:dynamicbeans.DynamicBean2dynamic.Validator

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

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

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

portletRequest.setAttribute("DynamicBean2", bean);

Form 项目的生命周期中,我调用 validator.validate(),它从会话中加载先前创建的 bean 对象(我正在运行 Websphere Portal Server)。 当我尝试将此对象转换回 DynamicBean2 时,它失败并出现 ClassCastException。

当我使用 .getClass() 将对象从会话中拉出

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

并检查它的类时,我得到 dynamicbeans.DynamicBean2。 这是我想要将其转换为的类,但是当我尝试时,我得到了 ClassCastException。

我收到这个有什么原因吗?

I have 2 different Java projects, one has 2 classes: dynamicbeans.DynamicBean2 and dynamic.Validator.

On the other project, I load both of these classes dynamically and store them on an Object

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

I then go ahead and create a Validator object using validatorClass.newInstance() and store it on validator then I create a bean object as well using beanClass.newInstance() and add it to the session.

portletRequest.setAttribute("DynamicBean2", bean);

During the lifecycle of the Form project, I call validator.validate() which loads the previously created bean object from the session (I'm running Websphere Portal Server). When I try to cast this object back into a DynamicBean2 it fails with a ClassCastException.

When I pull the object back out of the session using

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

and check the class of it using .getClass() I get dynamicbeans.DynamicBean2. This is the class I want to cast it to however when I try I get the ClassCastException.

Any reason why I'm getting this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

岁月染过的梦 2024-07-26 03:44:30

我不太明白您对程序流程的描述,但通常当您收到 ClassCastExceptions 时,您无法解释您已使用一个类加载器加载了该类,然后尝试将其转换为另一个类加载器加载的同一类。 这是行不通的——它们由 JVM 内的两个不同的 Class 对象表示,并且转换将会失败。

有一篇关于 WebSphere 中的类加载的文章。 我不能说它如何适用于您的应用程序,但有许多可能的解决方案。 我至少可以想到:

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

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

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

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

I am not quite following your description of the program flow, but usually when you get ClassCastExceptions you cannot explain you have loaded the class with one classloader then try to cast it to the same class loaded by another classloader. This will not work - they are represented by two different Class objects inside the JVM and the cast will fail.

There is an article about classloading in WebSphere. I cannot say how it applies to your application, but there are a number of possible solutions. I can think of at least:

  1. Change the context class loader manually. Requires that you can actually get a reference to an appropriate class loader, which may not be possible in your case.

    Thread.currentThread().setContextClassLoader(...);
    
  2. Make sure the class is loaded by a class loader higher in the hierarchy.

  3. Serialize and deserialize the object. (Yuck!)

There is probably a more appropriate way for your particular situation though.

赤濁 2024-07-26 03:44:30

在我的 Springboot 项目中添加对 spring-boot-devtools 的依赖项后,我遇到了这个问题。 我删除了依赖关系,问题就消失了。 在这一点上,我最好的猜测是 spring-boot-devtools 引入了一个新的类加载器,并且在某些情况下,某些情况下新的类加载器没有使用新的类加载器,这会导致不同类加载器之间出现类转换问题。线程。

参考:与Spring boot devtools相关的dozer映射异常

I was getting this problem after adding a dependency to spring-boot-devtools in my Springboot project. I removed the dependency and the problem went away. My best guess at this point is that spring-boot-devtools brings in a new classloader and that causes the issue of class casting problems between different classloaders in certain cases where the new classloader is not being used by some threads.

Reference: A dozer map exception related to Spring boot devtools

恰似旧人归 2024-07-26 03:44:30

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

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

The class objects were loaded in different classloaders, therefore the instances created from in each of classes are seen as 'incompatible'. This is a common issue in a an environment where there are many different classloaders being used and objects are being passed around. These issues can easily arise in Java EE and portal environments.

Casting an instance of a class requires that the Class linked to the object being casted is the same as the one loaded by the current thread context classloader.

一梦浮鱼 2024-07-26 03:44:30

当尝试使用 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
}

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

I got the A2AClassCastException problem when trying to create a List of objects from XML using Apache Commons Digester.

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
}

As stated above, the cause is that the digester doesn't use the same ClassLoader as the rest of the program. I ran this in JBoss, and it turned out that commons-digester.jar was not in JBoss's lib directory, but rather in a webapp's lib directory. Copying the jar into mywebapp/WEB-INF/lib also solved the problem. Another solution was to casll digester.setClassLoader(MyTemplate.class.getClassLoader()), but that feels like quite an ugly solution in this context.

晨曦÷微暖 2024-07-26 03:44:30

在 WildFly 10.1 上有相同的 my.package.MyClass 无法转换为 my.package.MyClass ,据我所知,我做了与 @Emil Lundberg 在他的答案中描述的相反的事情。

我已将模块(包含my.package.MyClass)添加到my.war/WEB-INF/jboss-deployment-struct.xml 作为依赖项

<dependencies>
    ...
    <module name="my.package"/>
</dependencies>

,并从 my.war/WEB-INF/lib 中删除相应的 jar,重新部署 WAR,然后代码按预期工作。

因此,我们确保它能解决问题。 现在,我们需要确保该问题不会再次出现,例如,当 WAR 的更新版本将被组装和部署时。

为此,在这些 WAR 的源中,需要为 jar 中的那些jar添加 provided code>pom.xml,这样下次注入修复/增强代码重新组装my.war时,就不会捆绑这个jar进入 my.war/WEB-INF/lib 。

Had the same my.package.MyClass cannot be cast to my.package.MyClass on WildFly 10.1 and, as I understand, I did the opposite to what @Emil Lundberg described in his answer.

I have added the module (which contains my.package.MyClass) to my.war/WEB-INF/jboss-deployment-structure.xml as a dependency

<dependencies>
    ...
    <module name="my.package"/>
</dependencies>

and removed the corresponding jar from my.war/WEB-INF/lib, re-deployed the WAR and then the code worked as expected.

Thus, we made sure it solves the issue. Now, we need to make sure the issue won't come back, for example, when the updated version of WAR will be assembled and deployed.

For this, in the sources of those WAR, it is required to add <scope>provided</scope> for those jar in pom.xml, so that when my.war is re-assembled next time with the fix/enhancement code injected, it will not bundle this jar into my.war/WEB-INF/lib.

毁梦 2024-07-26 03:44:30

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

为什么抛出的 ClassCastException 没有提及涉及的类加载器? - 我认为这将是非常有用的信息。
有谁知道将来是否会有类似的东西? 需要检查 20-30 个 Artifacts 的类加载器并不是那么令人愉快。 或者我在异常文本中遗漏了什么?

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

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

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

I had the same issue while using several JBoss instances on different machines. To bad I didn't stumble across this post earlier.
There were artifacts deployed on different machines, two of them declared class loaders with identical name.I changed one of the classloader names and everything worked fine => Beware of Copy&Paste!

Why doesn't the ClassCastException thrown mention the involved class loaders? - I think that would be very useful information.
Does anyone know if there will be anything like this available in the future? Needing to check the class loaders of 20-30 Artifacts is not that pleasant. Or is there something I missed in the exception text?

EDIT: I edited the META-INF/jboss-app.xml file and changed the name of the loader, the idea is to have a unique name. At work we use the artifact id(unique) combined with the version inserted by maven({$version}) during the build.
Using dynamic fields is only optional but helps if you want to deploy different versions of the same application.

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

You can find some info here: https://community.jboss.org/wiki/ClassLoadingConfiguration

开始看清了 2024-07-26 03:44:30

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

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

为我工作!

I had the same issue, and I finally found a workaround on java.net :

Copy all org.eclipse.persistence jar files from glassfish4/glassfish/modules to WEB-INF/lib. Then go in your glassfish-web.xml, and set class-delegate to false.

Worked for me !

笑看君怀她人 2024-07-26 03:44:30

我对 JAXB 和 JBoss AS 7.1 也有类似的问题。 此处描述了问题和解决方案:javax.xml.bind.JAXBException:此上下文已知类 *** 及其任何超类。 给出的异常是 org.foo.bar.ValueSet 无法转换为 org.foo.bar.ValueSet

I had a similar issue with JAXB and JBoss AS 7.1. The issue and solution are described here: javax.xml.bind.JAXBException: Class *** nor any of its super class is known to this context. The exception that was given was org.foo.bar.ValueSet cannot be cast to org.foo.bar.ValueSet

绝情姑娘 2024-07-26 03:44:30

我在 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,它将很好地找到本地接口,并且还可以毫无问题地执行方法(从同一容器上的单独应用程序),但是如果您错误地使用本地接口,模型对象不会被封送并且来自不同的类加载器。

I had the same issue on a wildfly EJB, The EJB was returning a list of Objects and has an remote and a local interface. I used the Local interface by mistake what was working just fine up until the point you try to cast the objects in the list.

Local/Remote interface:

public interface DocumentStoreService {

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

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

The EJB bean:

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

The correct spring wrapper around the 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>

Note the $Remote, You can change this to $Local and it will find the Local interface just fine, and also execute the methods without any issue (from a separate application on the same container), but the model objects are not marshaled and are from a different class loader if you use the local interface by mistake.

椵侞 2024-07-26 03:44:30

另一种选择:

在 weblogic 中发生在我身上,但我想它也可能发生在其他服务器中 - 如果你(只是)“发布”,因此你的一些类会被重新加载。 相反,执行“Clean”,以便所有类都将重新加载在一起。

Another option:

Happened to me in weblogic, but I guess it can happen in other servers as well - if you do (just) "Publish" and therefor some of your classes are re-loaded. Instead do "Clean" so all the classes will re-loaded together.

太傻旳人生 2024-07-26 03:44:30

我在从另一个 EJB 查找 EJB 时遇到了同样的问题。
我解决了将 @Remote(MyInterface.class) 添加到 EJB 类配置的问题

I had same problem with an EJB lookup from another EJB.
I solved adding @Remote(MyInterface.class) to EJB class configuration

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文