WebLogic Class 在 EJB Home 接口上投射

WebLogic Class Cast on EJB Home Interface

我们正在将 J2EE 应用程序 (EJB 2.0) 从 WebLogic Service 8.1 升级到 12c(12.2.1.1.0)。我们正在构建一个展开的 EAR 到域目录中的一个目录。 Web 应用程序 (struts) 在 JNDI 中执行查找并获取对 EJB 的引用和 returns 主页 class 就好了。我们遇到的问题是它无法转换为接口。

使用反射我们可以看到返回的 class 确实实现了预期的接口,但是当我们尝试转换它时它总是抛出一个 java.lang.ClassCastException。

工作原理是一个 class 加载器用于支持容器中的 EJB,另一个不相关的 class 加载器服务 servlet,因此返回的 class 无法转换为来自另一个 class 加载程序的接口 class。我们无法证实这一点,但我们怀疑 class 加载程序层次结构在 WLS 8.1 和 12c 之间发生了变化。如果是这样的话,我们就找不到解决办法了。

我们已经开始使用 WebLogic 类加载器分析工具,但这并不表示与此特定案例有关的任何 class 问题。

核心问题是我们必须更改什么才能使转换像 WebLogic 8.1 一样工作,从而避免重构现有代码?

明确地说,代码在 WebLogic Server 8.1 中有效,但在 WebLogic Server 12c 中无效。 EJB 部署描述符已更新为 weblogic.DDConverter,但我们在转换之前也遇到了这个问题。

这就是我们在 JndiHelper class 中查找 EJB 的方式(这适用于 WLS8):

public static EJBHome getHome( String ejbHomeName ) throws NamingException {
  EJBHome home = null;
  String sENCHome = JNDI_ENC_EJB_CONTEXT + "/" + ejbHomeName;
  Object objRef = new InitialContext().lookup( sENCHome );
  home = (EJBHome)PortableRemoteObject.narrow( objRef, EJBHome.class );
  return home;
}

下面是调用上面的代码,进行转换,如果失败则打印诊断信息:

EJBHome home = null;
try {
  home = JndiHelper.getHome( JndiConstants.USER_HANDLER_EJB );
  UserHandlerHome userHandlerHome = (UserHandlerHome)home; // throws class cast exception here
  UserHandler userHandler = userHandlerHome.create();
  adminInd = userHandler.isAdmin( userId );
} catch ( ClassCastException e ) {
  StringBuffer b = new StringBuffer( "ClassCastException: " );
  b.append( e.getMessage() );
  b.append( "\r\nThe JNDI lookup for '" );
  b.append( JndiConstants.USER_HANDLER_EJB );
  b.append( "' returned a bean of unexpected type.\r\nValue:" );
  b.append( home );
  b.append( "\r\nReturned bean's inheritance:\r\n" );
  b.append( Reflector.getInheritanceDump( home ) );
  b.append( "\r\n" );
  b.append( UserHandlerHome.class.getName() );
  b.append( " expected.\r\nFull Stack Trace:\r\n" );
  b.append( ExceptionUtil.stackTrace( e ) );
  Logger.error( this, b.toString() );
  errors.add( ActionErrors.GLOBAL_ERROR, new WebActionError( MessageConstants.NON_DESCRIPT_ERROR, WebActionError.makePopUp( b.toString() ) ) );
}

这是显示的诊断信息示例。请注意,继承列表包含以“(I)”为后缀的类型和接口:

ERROR com.myapp.admin.controller.UserHelper - ClassCastException: com.myapp.admin.model.UserHandler_8cwrmw_HomeImpl cannot be cast to com.myapp.admin.model.UserHandlerHome
The JNDI lookup for 'UserHandler' returned a bean of unexpected type.
Value:com.myapp.admin.model.UserHandler_8cwrmw_HomeImpl@5f938f12
Returned bean's inheritance:
com.myapp.admin.model.UserHandler_8cwrmw_HomeImpl
weblogic.ejb.container.internal.StatelessEJBHome
weblogic.ejb.container.internal.BaseEJBHome
java.lang.Object
weblogic.ejb.container.interfaces.BaseEJBRemoteHomeIntf(I)
weblogic.ejb.container.interfaces.BaseEJBHomeIntf(I)
weblogic.ejb.spi.BaseEJBHomeIntf(I)
weblogic.ejb20.interfaces.RemoteHome(I)
javax.ejb.EJBHome(I)
java.rmi.Remote(I)
weblogic.ejb.spi.RemoteHome(I)
weblogic.rmi.SupportsInterfaceBasedCallByReference(I)
com.myapp.admin.model.UserHandlerHome(I)
com.myapp.admin.model.UserHandlerHome expected.
Full Stack Trace:
java.lang.ClassCastException: com.myapp.admin.model.UserHandler_8cwrmw_HomeImpl cannot be cast to com.myapp.admin.model.UserHandlerHome
        at com.myapp.admin.controller.UserHelper.isAdmin(UserHelper.java:82)
        at com.myapp.framework.controller.login.LoginAction.doAction(LoginAction.java:278)
        at com.myapp.framework.controller.AfgAction.perform(AfgAction.java:268)
        at org.apache.struts.action.ActionServlet.processActionPerform(ActionServlet.java:1888)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1654)
        at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:526)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:286)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:260)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:137)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:350)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:247)
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3679)
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3649)
        at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:326)
        at weblogic.security.service.SecurityManager.runAsForUserCode(SecurityManager.java:197)
        at weblogic.servlet.provider.WlsSecurityProvider.runAsForUserCode(WlsSecurityProvider.java:203)
        at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:71)
        at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2433)
        at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2281)
        at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2259)
        at weblogic.servlet.internal.ServletRequestImpl.runInternal(ServletRequestImpl.java:1686)
        at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1646)
        at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:270)
        at weblogic.invocation.ComponentInvocationContextManager._runAs(ComponentInvocationContextManager.java:348)
        at weblogic.invocation.ComponentInvocationContextManager.runAs(ComponentInvocationContextManager.java:333)
        at weblogic.work.LivePartitionUtility.doRunWorkUnderContext(LivePartitionUtility.java:54)
        at weblogic.work.PartitionUtility.runWorkUnderContext(PartitionUtility.java:41)
        at weblogic.work.SelfTuningWorkManagerImpl.runWorkUnderContext(SelfTuningWorkManagerImpl.java:640)
        at weblogic.work.ExecuteThread.execute(ExecuteThread.java:406)
        at weblogic.work.ExecuteThread.run(ExecuteThread.java:346)

在我们的 WEB-INF\weblogic.xml 中,我们有以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>

    <jsp-descriptor>
        <keepgenerated>true</keepgenerated>
        <backward-compatible>true</backward-compatible>
    </jsp-descriptor>

    <container-descriptor>
        <prefer-application-packages>
            <!-- Resolves finding Log4J classes (Issue T9) -->
            <package-name>org.apache.log4j.*</package-name>
            <package-name>org.apache.log4j.pattern.*</package-name>
            <package-name>org.apache.log4j.net.*</package-name>
            <package-name>org.apache.log4j.jmx.*</package-name>
            <package-name>org.apache.log4j.jdbc.*</package-name>
            <package-name>org.apache.log4j.helpers.*</package-name>
            <package-name>org.apache.log4j.config.*</package-name>
            <!-- Recommended by the Classloader Analysis Tool to resolve reported conflicts -->
            <package-name>com.myapp.admin.*</package-name>
            <package-name>com.myapp.framework.*</package-name>
            <package-name>com.myapp.om.*</package-name>
            <package-name>com.sun.mail.*</package-name>
            <package-name>javax.mail.*</package-name>
            <package-name>javax.mail.event.*</package-name>
            <package-name>javax.mail.internet.*</package-name>
            <package-name>javax.mail.search.*</package-name>
            <package-name>javax.wsdl.*</package-name>
            <package-name>javax.wsdl.extensions.*</package-name>
            <package-name>javax.wsdl.factory.*</package-name>
            <package-name>javax.wsdl.xml.*</package-name>
            <package-name>javax.xml.rpc.*</package-name>
            <package-name>org.apache.commons.*</package-name>
        </prefer-application-packages>
    </container-descriptor>

</weblogic-web-app>

如有任何帮助,我们将不胜感激。

我们通过从 weblogic.xml 中删除 <prefer-application-packages> 解决了这个问题,这导致 weblogic.utils.classloaders.ChangeAwareClassLoader 加载它自己的界面版本及其父界面 weblogic.utils.classloaders.GenericClassLoader支持了申请。由于 Web 应用程序试图转换为与由不同 class 加载程序解析的 EJB 中的接口版本不匹配的接口版本,因此不允许转换。