For several days now I've been trying to get to the bottom of the error:

view plain print about
1"Error","jrpp-0", tried to access class javax.mail.internet.ContentDisposition from class coldfusion.mail.RFC2231Util The specific sequence of files included or processed is: C:CFusionMX7wwwrootcontentdisposition.cfm, line: 2
2java.lang.IllegalAccessError: tried to access class javax.mail.internet.ContentDisposition from class coldfusion.mail.RFC2231Util
3    at coldfusion.mail.RFC2231Util.setFileName(
4    at coldfusion.mail.MailImpl.setAttachment(
5    at
6    at coldfusion.runtime.CfJspPage._emptyTag(
7    at cfcontentdisposition2ecfm1804490529.runPage(C:CFusionMX7wwwrootcontentdisposition.cfm:2)

The error occurred on a new installation of CFMX 7.01 on Windows that was serving code migrated from a ColdFusion 4.5 server. The following simple test case for CFMAIL was sufficient to produce the error:

view plain print about
1[cfmail from="" to="" subject="test">
2    [cfmailparam file="#cgi.cf_template_path#">
3This is a test

While troubleshooting the problem on my local server, I configured exactly the same installation type down the same build number, updater, and even used the same jvm.config as the problem server. Still, I was not able to reproduce the error.

The Sun Java Documentation on IllegalAccessError shows that it derives from IncompatibleClassChangeError, and states the following:
Thrown if an application attempts to access or modify a field, or to call a method that it does not have access to.

Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.

From there I decided to test loading the class shown as the culprit of the IllegalAccessError and dumping its methods, just to simplify the problem and eliminate CFMAIL altogether.

view plain print about
2     myObj = createObject("java","javax.mail.internet.ContentDisposition");
4[cfdump var="#myObj#"/>

The result on my local server was a long list of methods on the class instance (CFDUMP uses the Java Reflection API to determine methods available from a Java Class), but on the problem server this resulted in a short list of 2 methods followed by several occurrances of the IllegalAccessError again. Something was obviously different about the ContentDisposition class. This class is part of the javax.mail.internet package that is built into cf_root/lib/mail.jar, where mail.jar provides the implementation of JavaMail 1.3.2.

Reviewing the Java Class Path shown in the problem server's System Information page of the CF Admin confirmed that the correct mail.jar was loaded and that no other mail.jar was in the classpath. One test that came to mind was to use the JVM switch for -verbose:class which writes to the server's out.log every class that gets loaded as it gets loaded. This produced the same result on both my local server and the problem server, simply a line stating that javax/mail/internet/ContentDisposition.class was loaded. Not very helpful, and by now I was pulling my hair out.

What I needed was a way to know from which jar file was the class loaded in order to confirm that the class shown in the error was indeed the anticipated class file in cf_root/lib/mail.jar, or rather some other rogue jar file that snuck into the class path instead. It was just then that Dave S, a colleague of mine walked in and promptly responded to my inquiry,
"Oh yeah, I 've got some code that will show from which jar a class got loaded".

Beautiful! This better work!

view plain print about
1[cffunction name="resolveResource" returnType="string">
2    [cfargument name="resource" required="Yes">
3    [cfset var resourceURL = getClass().getClassLoader().getResource(resource)>
4    [cfif isDefined("resourceURL")>
5        [cfreturn resourceURL>
6    [/cfif>
7    [cfreturn "could not resolve resource">

Running this on the local server confirmed that it did come from cf_root/lib/mail.jar, but running it on the problem server finally produced an explanation to the problem.

view plain print about
1jar:file:/C:/CFusionMX7/runtime/lib/CFX_SOAP.jar! /javax/mail/internet/ContentDisposition.class

Ah ha! There's the problem.

CFX_SOAP is a third-party Java CFX tag which provided SOAP functionality for pre-MX ColdFusion Servers. The CFX's documentation instructs to place the jar file in CFusion/Java/Classes. When my customer performed the code migration from CF 4.5 manually, it was decided that this jar file should go into CFMX 7's runtime/lib directory. The customer's application was dependent this jar file, so even though SOAP-based Web Services are provided as part of basic ColdFusion MX 6/7 functionality, the customer had not yet updated to the code to take advantage of it.

The problem was caused by CFX_SOAP.jar being in runtime/lib which puts the jar file in the Server Class Path, ahead of the CF Class Path, so when coldfusion.mail.RFC2231Util.setFileName() needed to create a new instance of ContentDisposition it first found an older version of the class embedded in the same package heirarchy within CFX_SOAP.jar, occluding the other ContentDisposition class in cf_root/lib/mail.jar. The appropriate place for third-party jar files is cf_root/wwwroot/WEB-INF/lib/ where they will be loaded after the CF Class Path and limited in scope to that particular J2EE Web Application, and therefore not interfere with any built-in ColdFusion server functionality. Classes or jar files placed in runtime/lib have a scope that spans across all server instances and all web applications on those servers, and will come first in the class path. Moving the CFX_SOAP.jar to WEB-INF/lib/ resolved the problem.