NoClassDefFoundError during deployment in glassfish 3.1 due to wrong classloader
scic.dunasdan.gmx.ch Mar 10, 2011 7:28 AMWe had a problem deploying our EAR wich contained a WAR in Glassfish 3.1 final. It deployed perfectly in Glassfish 3.0.1.
We got a NullPointerException during deployment wich turned out to be a NoClassDefFoundError when Weld tried to compile a proxy.
Daemon Thread [admin-thread-pool-4848(5)] (Suspended (exception CannotCompileException)) ClassFileUtils.toClass(ClassFile, ClassLoader, ProtectionDomain) line: 117 InterceptedSubclassFactory<T>(ProxyFactory<T>).createProxyClass(String) line: 402 InterceptedSubclassFactory<T>(ProxyFactory<T>).getProxyClass() line: 283 ManagedBean<T>(AbstractClassBean<T>).createEnhancedSubclass() line: 673 ManagedBean<T>(AbstractClassBean<T>).initEnhancedSubclass() line: 659 ManagedBean<T>(AbstractClassBean<T>).initializeAfterBeanDiscovery() line: 354 ManagedBean<T>.initializeAfterBeanDiscovery() line: 420 BeanDeployment.doAfterBeanDiscovery(List<Bean<?>>) line: 232 BeanDeployment.afterBeanDiscovery(Environment) line: 221 WeldBootstrap.deployBeans() line: 369 WeldDeployer.event(EventListener$Event) line: 170 EventsImpl.send(EventListener$Event, boolean) line: 128 EarDeployer$CompositeApplicationInfo(ApplicationInfo).load(ExtendedDeploymentContext, ProgressTracker) line: 262 ApplicationLifecycle.deploy(Collection<Sniffer>, ExtendedDeploymentContext) line: 460 ApplicationLifecycle.deploy(ExtendedDeploymentContext) line: 240 DeployCommand.execute(AdminCommandContext) line: 370 CommandRunnerImpl$1.execute(AdminCommandContext) line: 355 CommandRunnerImpl.doCommand(CommandModel, AdminCommand, AdminCommandContext) line: 370 CommandRunnerImpl.doCommand(CommandRunnerImpl$ExecutionContext, AdminCommand) line: 1067 CommandRunnerImpl.access$1200(CommandRunnerImpl, CommandRunnerImpl$ExecutionContext, AdminCommand) line: 96 CommandRunnerImpl$ExecutionContext.execute(AdminCommand) line: 1247 CommandRunnerImpl$ExecutionContext.execute() line: 1235 PublicAdminAdapter(AdminAdapter).doCommand(String, GrizzlyRequest, ActionReport, Payload$Outbound) line: 465 PublicAdminAdapter(AdminAdapter).service(GrizzlyRequest, GrizzlyResponse) line: 222 PublicAdminAdapter(GrizzlyAdapter).service(Request, Response) line: 168 HK2Dispatcher.dispath(Adapter, ClassLoader, Request, Response) line: 117 ContainerMapper.service(Request, Response) line: 234 ProcessorTask.invokeAdapter() line: 822 ProcessorTask.doProcess() line: 719 ProcessorTask.process(InputStream, OutputStream) line: 1013 DefaultProtocolFilter.execute(Context) line: 225 HttpProtocolChain(DefaultProtocolChain).executeProtocolFilter(Context, int) line: 137 HttpProtocolChain(DefaultProtocolChain).execute(Context, int) line: 104 HttpProtocolChain(DefaultProtocolChain).execute(Context) line: 90 HttpProtocolChain.execute(Context) line: 79 ProtocolChainContextTask.doCall() line: 54 ProtocolChainContextTask(SelectionKeyContextTask).call() line: 59 ProtocolChainContextTask(ContextTask).run() line: 71 SyncThreadPool$SyncThreadWorker(AbstractThreadPool$Worker).doWork() line: 532 SyncThreadPool$SyncThreadWorker(AbstractThreadPool$Worker).run() line: 513 HttpWorkerThread(Thread).run() line: 619
We have a web module (war) in the ear and we have libs in the war. All of the above contain BDAs. The problem was that it tried to load a class from the war module with the ear class loader, but it should have used the WebAppClassloader.
So in the call to ClassFileUtils.toClass(proxyClassType, cl, domain) in the in the method createProxyClass of org.jboss.weld.bean.proxy.ProxyFactory the cl param was the EarClassLoader but it should have been the WebappClassloader. Fortunately ProtectionDomain in the method contains the correct WebappClassloader.
It seams the method resolveClassLoaderForBeanProxy in org.jboss.weld.bean.proxy.ProxyFactory got the wrong classLoader?
So we added the following lines before the call to ClassFileUtils.toClass in the createProxyClass method which fixed the issue:
ClassLoader cl = classLoader; if (domain != null) { ClassLoader domainCl = domain.getClassLoader(); if (domainCl != null) { cl = domainCl; } }
The funny thing is the error shown above was not thrown consistently. After redeploying the app several times, deployment worked sometimes. With each try to it couldn't find a different class. In theend it could find all classes and deployed. With the above fix the deployment works everytime and the app works perfectly.
Has anyone experienced similar issues? Is it a Weld bug or a bug in the glassfish 3.1 org.jboss.weld.serialization.spi.ProxyServices implementation? Is there a problem with our ear setup?