4

I have a workaround for my specific error, which is to add the path C:\ColdFusion10\cfusion\wwwroot\WEB-INF\classes to the ColdFusion Class Path setting. However, I'm not sure why that is necessary. Details below:

I have been using a legacy [I don't know who wrote it or where it came from] Java class in ColdFusion 9 to help read and parse mailbox files. When I upgraded to ColdFusion 10 it stopped working. Here's a brief example:

<cfset archive = createObject("Java", "its.util.MBoxReader")>
<cfdump var="#archive#">

On CF9 that works. On CF10 it produces this message:

Object instantiation exception. An exception occurred while instantiating a Java object. The class must not be an interface or an abstract class. Error: javax/mail/Store.

Here's the stack trace:

java.lang.NoClassDefFoundError: javax/mail/Store at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Class.java:2317) at java.lang.Class.privateGetPublicFields(Class.java:2350) at java.lang.Class.getFields(Class.java:1378) at coldfusion.runtime.java.ObjectHandler.Initialize(ObjectHandler.java:35) at coldfusion.runtime.java.ObjectHandler.(ObjectHandler.java:30) at coldfusion.runtime.java.ReflectionCache.get(ReflectionCache.java:38) at coldfusion.runtime.java.JavaProxy.(JavaProxy.java:35) at coldfusion.runtime.java.JavaProxyFactory.getProxy(JavaProxyFactory.java:121) at coldfusion.runtime.ProxyFactory.getProxy(ProxyFactory.java:65) at coldfusion.runtime.CFPage.createObjectProxy(CFPage.java:5757) at coldfusion.runtime.CFPage.CreateObject(CFPage.java:5720) at coldfusion.runtime.CFPage.CreateObject(CFPage.java:5654) at coldfusion.runtime.CFPage.CreateObject(CFPage.java:5629) at coldfusion.runtime.CFPage.CreateObject(CFPage.java:5576) at cfindex2ecfm915725705.runPage(C:\ColdFusion10\cfusion\wwwroot\mbox\index.cfm:1) at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:244) at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:444) at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65) at coldfusion.filter.IpFilter.invoke(IpFilter.java:64) at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:449) at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48) at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40) at coldfusion.filter.PathFilter.invoke(PathFilter.java:112) at coldfusion.filter.LicenseFilter.invoke(LicenseFilter.java:30) at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:94) at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79) at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28) at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46) at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62) at coldfusion.CfmServlet.service(CfmServlet.java:219) at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42) at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:414) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:298) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:722) Caused by: java.lang.ClassNotFoundException: javax.mail.Store at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1688) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1533) ... 55 more

However, if I add this to my test page, CF10 is able to find & load javax.mail.Store:

<cfset store = createObject("Java", "javax.mail.Store")>
<cfdump var="#store#">

javax.mail.Store is present in the mail.jar files included with ColdFusion and are located in C:\ColdFusion9\lib and C:\ColdFusion10\cfusion\lib on CF9 and CF10, respectively.

MboxReader.class is located in C:\ColdFusion9\wwwroot\WEB-INF\classes\its\util and C:\ColdFusion10\cfusion\wwwroot\WEB-INF\classes\its\util (CF9 and CF10, respectively).

If I manually add C:\ColdFusion10\cfusion\wwwroot\WEB-INF\classes to the ColdFusion Class Path in the CF administrator it works.

I'm not sure why ColdFusion can find the class, but the MboxReader class cannot unless I add the classpath. According to About ColdFusion, Java, and J2EE, ColdFusion should load the classes in WEB-INF/classes.

Update:

The parent class loader of the archive object:

coldfusion.bootstrap.BootstrapClassLoader

The parent class loader of the javax.mail.Store object:

org.apache.catalina.loader.WebappClassLoader
cherdt
  • 303
  • 4
  • 14
  • 1
    As an aside, why are you using `classes`? Typically multiple class files are bundled in jars and stored in `lib`. Among other things, it is a lot easier to manage a single jar file than bunches of individual .class files. – Leigh Dec 06 '13 at 12:54
  • This preceded my tenure, but I think the idea was that it would be easier to deploy updates to single classes rather than repackaging a jar file each time. It turns out that the classes are rarely updated and probably should be bundled. – cherdt Dec 06 '13 at 16:57
  • 1
    Maybe this stuff was created before the advent of tools like Ant that can build the jar for you with the click of a button? To my way of thinking separate classes makes things harder to deploy because there are more moving pieces. Plus it is more likely different classes will get out of synch. With a jar, it is only one file every time. BTW, I meant to ask - does your custom java stuff also include the mail classes in the `classes` directory - or does it just rely on the fact that it is already bundled with CF? – Leigh Dec 06 '13 at 18:37
  • The custom Java does not include the mail classes, it relies on CF's mail.jar. When I copy mail.jar from C:\ColdFusion10\cfusion\libs to C:\ColdFusion10\cfusion\wwwroot\WEB-INF\libs it works! That definitely seems to indicate a class loader issue, as you and @jhadesdev have both suggested. Including an extra copy of mail.jar seems like a better solution to me than adding what is supposed to be a directory for dynamically-loaded classes to the classpath. – cherdt Dec 06 '13 at 21:06

1 Answers1

4

It seems some class depends on javax.mail.Store, but it cannot find it at runtime. If you could post the full stacktrace we can see which class it is.

Try to see how the chain of classloaders is set up in coldfusion, WEB-INF/classes is included by default, and then all jars of WEB-INF/lib.

EE servers can be configured to look first on the server and only then on WEB-INF/classes / WEB-INF/lib. This configuration is both server and application specific, with different defaults per server (Tomcat defaults are different than websphere, etc.).

If Coldfusion uses Java 7 you can use JHades to print the classloader chain and do some queries on the classpath, to see where the different versions of the several problematic classes are.

Try to answer these questions, you can always post partial findings:

  • Which class is not finding java.mail.Store

  • In which class loader does the class that is throwing the exception resides

  • For the problematic classes (javax.mail.Store and the class that is not finding it) post the different versions present on the classpath, per classloader (JHades could help with that)

  • How is the classloader chain setup configured, what are the configured priorities etc.

Angular University
  • 42,341
  • 15
  • 74
  • 81
  • I was going to suggest something similar ie class loader problem. However, to clarify - it is not that CF cannot find the class per se, rather the jvm had a problem *loading* it. CF already includes mail jars (two versions IIRC). So things can get a little wonky depending on which class loader ends up loading your custom object and/or ...(cont'd) – Leigh Dec 06 '13 at 12:51
  • .. if your stuff also includes a version of the mail jars/classes. I suspect adding the location to the class path ends up changing the parent class loader of your object, so that the mail jar is now "accessible" according to the [class loader hierachy rules](http://stackoverflow.com/questions/15506237/getting-coldfusion-called-web-service-to-work-with-javaloader-loaded-objects/15592095#15592095). @jhadesdev - *RE: different defaults per server* Yeah, I am pretty sure CF customizes the loading order. Though I'm not sure exactly what the rules are ... – Leigh Dec 06 '13 at 13:01
  • I added the full stack trace to the post. I haven't successfully run JHades yet and so I don't have answers to your other questions yet, but based on your comments and @Leigh's comments it definitely appears to be a class loader issue. – cherdt Dec 06 '13 at 21:19
  • @cherdt - If you get a chance, can you dump the parent class loader of `archive`. What does it report? I'm curious about its parent... – Leigh Dec 06 '13 at 21:53
  • @Leigh, I'm not sure how to get that information. How do you access the parent class loader? – cherdt Dec 06 '13 at 23:42
  • @chrdt - IIRC, it should just be `yourVariable.getClass().getClassLoader()`. – Leigh Dec 06 '13 at 23:51
  • It seems CF10 uses a modified tomcat internally, as oposed to CF9 (we can confirm that based on the stacktrace which begins with tomcat catalina packages).Then this CF initialization method coldfusion.runtime.java.ObjectHandler.Initialize tries to load a javamail class and it fails. Is javamail correctly installed on the CF server, is it supposed to be installed? In tomcat the recommended way based on their documentation is to drop a couple of jars on a server lib directory http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#JavaMail_Sessions, check Install the JavaMail libraries – Angular University Dec 07 '13 at 15:34
  • CF includes the mail jars automatically for the built in `cfmail` functionality. Since the custom setup is designed specifically for all of the existing CF tags/functions just be careful when mucking with the setup (unless its a dev machine). It is very easy to break existing tags/functions if you do not know what you are doing and how the various pieces fit together. (I'm not knocking jhadesdev's advice. Just be aware of the possible repercussions, and have a restore plan, *before* making changes on a prod machine) – Leigh Dec 07 '13 at 19:25