【问题标题】:ClassCastException when casting looked-up EJB view in AS7在 AS7 中投射查找的 EJB 视图时出现 ClassCastException
【发布时间】:2011-09-01 11:33:10
【问题描述】:

我在 JBoss AS 7.1.0.Alpha1-SNAPSHOT(7.0.1.Final 版本后)上部署了 2 个 EAR。两者都部署良好。

我有一个 EJB Singleton 类打包在一个 JAR 中,在其中一个 EAR 中:

@Startup
@Singleton
// one of @Local(Store.class), @Remote(Store.class), @LocalBean
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@Transactional(TransactionPropagation.SUPPORTS)
public class StoreFront implements Store {
...


public interface Store {
...

当它部署时,它说 EJB 被绑定到:

"java:app/store-core-2011.1.2-SNAPSHOT/StoreFront"
"java:app/store-core-2011.1.2-SNAPSHOT/StoreFront!uk.co.magus.jam.store.core.Store"
"java:module/StoreFront"
"java:module/StoreFront!uk.co.magus.jam.store.core.Store"
"java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront!uk.co.magus.jam.store.core.Store"
"java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront"

到目前为止,一切都很好。当我尝试通过 JNDI 从 OTHER 部署的 EAR 内的 JAR 内的非 CDI、非 EJB 类中查找它时,只能在“全局”下的 JNDI 名称上找到它——再次,预期。

但是,当我尝试将生成的对象转换为实际的接口类时:

Object lookupObject = new InitialContext().lookup(jndiName);
Store store = (StoreFront)lookupObject;

我得到以下异常:

11:17:52,402 ERROR [jam.core.link.LinkListener] (Thread-45) Exception when casting to Store after lookup with [java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront]: java.lang.ClassCastException: jam.store.core.Store$$$view1 cannot be cast to jam.store.core.Store
    at jam.core.link.LinkListener.getStore(LinkListener.java:108) [core-jar-2011.1.2-SNAPSHOT.jar:]
    at jam.core.link.LinkListener.postLoad(LinkListener.java:27) [core-jar-2011.1.2-SNAPSHOT.jar:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_07]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_07]
    at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_07]
    at org.hibernate.ejb.event.ListenerCallback.invoke(ListenerCallback.java:48)
    at org.hibernate.ejb.event.EntityCallbackHandler.callback(EntityCallbackHandler.java:96)
    at org.hibernate.ejb.event.EntityCallbackHandler.postLoad(EntityCallbackHandler.java:89)
    at org.hibernate.ejb.event.EJB3PostLoadEventListener.onPostLoad(EJB3PostLoadEventListener.java:49)
    at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:264)
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1012)
    at org.hibernate.loader.Loader.doQuery(Loader.java:889)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2058)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:81)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:71)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3686)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:446)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:427)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:204)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:251)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:148)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:947)
    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:863)
    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:856)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:787)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:762)
    at org.jboss.as.jpa.container.AbstractEntityManager.find(AbstractEntityManager.java:220) [jboss-as-jpa-7.1.0.Alpha1-SNAPSHOT.jar:7.1.0.Alpha1-SNAPSHOT]
    at jam.core.dao.GenericDAO.findById(GenericDAO.java:87) [core-jar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.HarvesterDAOUtil.loadLink(HarvesterDAOUtil.java:251) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.1779224926$Proxy$_$$_WeldSubclass.loadLink(1779224926$Proxy$_$$_WeldSubclass.java) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_07]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_07]
    at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_07]
    at org.jboss.interceptor.proxy.SimpleInterceptionChain.invokeNextInterceptor(SimpleInterceptionChain.java:112) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.interceptor.proxy.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:119) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:194) [seam-persistence-3.0.0.Final.jar:]
    at org.jboss.seam.transaction.Work.workInTransaction(Work.java:54) [seam-persistence-3.0.0.Final.jar:]
    at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:188) [seam-persistence-3.0.0.Final.jar:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_07]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_07]
    at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_07]
    at org.jboss.interceptor.proxy.InterceptorInvocation$InterceptorMethodInvocation.invoke(InterceptorInvocation.java:72) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.interceptor.proxy.SimpleInterceptionChain.invokeNextInterceptor(SimpleInterceptionChain.java:82) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:133) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:112) [jboss-interceptor-core-2.0.0.Alpha3.jar:2.0.0.Alpha3]
    at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:65) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]
    at harvest.service.1779224926$Proxy$_$$_WeldSubclass.loadLink(1779224926$Proxy$_$$_WeldSubclass.java) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.CombineHarvester.workOnLinkId(CombineHarvester.java:259) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.CombineHarvester.harvestCache(CombineHarvester.java:223) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.CombineHarvester.performHarvest(CombineHarvester.java:136) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at harvest.service.CombineHarvester.run(CombineHarvester.java:107) [harvest-sar-2011.1.2-SNAPSHOT.jar:]
    at java.lang.Thread.run(Thread.java:619) [:1.6.0_07]

EJB 是否使用任何一个注释

@Local(Store.class)
@Remote(Store.class)
@LocalBean 

没有区别。据我了解,它返回代理“视图”的事实是正常的。但是,我不应该能够将该视图投射到界面上吗?我使用的全局 JNDI 名称的组合以及我是否投射到 Store 或 StoreFront 似乎也没有任何区别 - 无法投射任何组合,即使异常类似于 jam.store.core.Store$$$view1 cannot be cast to jam.store.core.Store,具有匹配的(基)类名称

谁能指出我做错了什么?

【问题讨论】:

    标签: java ejb jndi classcastexception jboss7.x


    【解决方案1】:

    这是 AS7 中的一个错误:https://issues.jboss.org/browse/AS7-1658

    一种可能的解决方法是不强制转换返回的对象,然后通过reflection 使用它来触发方法。不过很笨重。

    【讨论】:

      【解决方案2】:

      更好的方法是在 jboss 模块中部署共享接口,并将该模块包含在两个工件的类路径中(使用 maven 时)

                      <archive>
                          <manifestEntries>
                              <Dependencies>${jboss.nonjee.modules}</Dependencies>
                          </manifestEntries>
                      </archive>
      

      【讨论】:

      • 啊,我没有意识到这一点。目前对我们来说不是一个选择,但很重要。
      【解决方案3】:

      我也得到了这篇评论的帮助;):

      David Lloyd 添加了评论 - 07/Mar/12 下午 4:02 这是因为您使用的是本地接口。使用本地接口时,您可能只有一个接口类的副本(这就是使其成为本地接口的原因)。切换到使用远程接口(或者,使用 Class-Path 获取本地接口而不是复制它们),问题应该会消失。

      【讨论】:

        【解决方案4】:

        我遇到了同样的问题;试图将 Interface 类作为一个单独的模块并将其包含在一个 Ear 中,并将其作为提供的一个 Ear 包含在另一个 Ear 中; 在 JBOSS 中,每个 EAR 中的类由单独的类加载器加载。因此,如果一个 EAR 有 Class A ,而另一个 EAR 有相同的 Class A ,那么你会得到一个类转换异常。因此,在第二个 EAR 中提供所提供的依赖项,并在 jboss-deployment-structure.xml 中添加第一个 EAR 作为模块依赖项。请注意,动态模块依赖性可能保证 EAR 文件名是恒定的;您可以在 EAR 文件的构建标记下指定 &lt;finalName&gt; 来修复此问题

        还将查找从本地更改为远程 - 见下文,并在两个模块中包含包含接口的 maven 模块

        //jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        
        TO
            jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.remote.client.InitialContextFactory");
        

        您可能希望将查找从 java:app 更改为 java:global

        final javax.naming.Context context = new InitialContext(jndiProperties);
                AsyncFutureItf  test =(AsyncFutureItf)context.lookup
                        //("java:app/Executor/AsyncFutureTest!pacakge.AsyncFutureItf");
                        ("java:global/ExecutorEar/Executor/AsyncFutureTest!package.AsyncFutureItf");
        

        而且由于耳朵通常使用这样的版本注册

        java:global/ExecutorEar-<version>/Executor/AsyncFutureTest!package.AsyncFutureItf
        

        并且您不想在代码中进行版本驱动的查找,您还需要做两件事。在 EAR builder maven 目录 (src\main\resources\application.xml) 中的 application.xml 中,您需要添加“应用程序名称”标签,如

            <?xml version="1.0" encoding="UTF-8"?>
        <application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" version="5">
          <description>Task Controller EAR</description>
          <display-name>TaskControllerEAR</display-name>
          <application-name>TaskControllerEAR</application-name>
          <module>
            <ejb>TaskController.jar</ejb>
          </module>
          <library-directory>lib</library-directory>
        </application>
        

        并在你的 pom 中生成你需要提供对 application.xml 的引用的 pom,比如

        <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-ear-plugin</artifactId>
                    <version>2.4.2</version>
                    <configuration>
                        <version>5</version>
                        <defaultLibBundleDir>lib</defaultLibBundleDir>
                        <earSourceDirectory>src/main/resources</earSourceDirectory>
                        <applicationXml>${project.basedir}/src/main/resources/application.xml</applicationXml>
        

        ...

        <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
              <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
        
        
              <sub-deployment name="MROControllerRest.war">
                        <exclusions>
                                  <module name="org.apache.commons.logging" />
                                  <module name="org.slf4j" />
                                  <module name="org.slf4j.ext" />
                                  <module name="org.slf4j.jcl-over-slf4j" />
                                  <module name="org.slf4j.impl" />
                                  <module name="org.apache.log4j" />
                        </exclusions>
                        <dependencies>
                            <module name="org.slf4j" slot="1.7.5" />
                            <module name="logger" />
                            <module name="deployment.TaskControllerEAR.ear.TaskController.jar" export="TRUE"/>
        
                        </dependencies>
        

        这里是堆栈跟踪供参考

        java.lang.ClassCastException: com.package.TaskSplitterItf$$$view210 cannot be cast to com.package.TaskSplitterItf
        

        【讨论】:

        • 在 web 模块的 pom 文件中将 ejb 模块的依赖范围更改为 'provided' 解决了类转换异常问题。谢谢。
        【解决方案5】:

        如果您的 EJB 客户端位于 EAR 中,而 EJB 实现位于另一个“服务”-EAR 中,并且您在 EJB 上调用 @Remote 接口方法返回复杂的对象而不是原始类型,也会出现同样的问题。被返回的复杂对象也被声明为一个接口,被正确地声明、已知并且对 EJB 客户端可用。返回的 Object 实现与目标 EJB 实现一起包含在“服务”-EAR 中。 尽管有这样一致的代码,JBoss 在 Class cast 异常上还是失败了。

        我注意到您确实可以保留一个@Remote 接口来声明所有目标 EJB 方法,但只能对这些方法返回的所有对象使用普通类声明。如果将返回的对象声明为接口,则 JBoss 中会出现类转换异常。

        这是 JBoss 中的一个限制(或错误);它确实在 Glassfish 和 WebLogic 中工作,我们曾经运行过相同的代码。

        【讨论】:

          【解决方案6】:

          如果您的 EAR 中多次包含带有 EJB 的 jar 文件,则会出现同样的问题。

          示例:

          你有

          • 一个包含所有 EJB 的 myEJB.jar 文件
          • 包含您的网络类/资源的 myWebApp.war
          • 一个包含 myEJB.jar 和 myWebApp.jar 的 myEnterprise.ear

          如果您的 myWebApp.war 还包含自己的 myEJB.jar,那么您将遇到此错误 (ClassCastExc)。似乎 EJB 对象是在 myEnterprise.ear 的 myEJB.jar 中创建的。如果您随后将此对象强制转换为 myWebApp.war 内的 myEJB.jar 的同一类,这将不起作用,因为这是在另一个 jar 中定义的类。

          如果您遇到此错误,您必须从您的 war 文件中删除 myEJB.jar 并且 ClassCastExc 已消失...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-12-29
            • 1970-01-01
            • 2011-02-18
            • 2018-08-25
            • 2014-08-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多