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 中的接口版本不匹配的接口版本,因此不允许转换。
我们正在将 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 中的接口版本不匹配的接口版本,因此不允许转换。