I am viewing the Apache POI docs, both the ones that came with my download, and the ones on the live site. There should be a setParagraph()
method in the org.apache.poi.xwpf.usermodel.XWPFDocument
class. I am consuming this class in ColdFusion, and am unable to access many of the methods listed in the docs.
Is this due to consuming the class or possibly class dependencies improperly? Or is this due to Apache POI .jars being updated and no longer supporting the setParagraph()
method?
Update:
I am using ColdFusion 9 and am loading the classes using JavaLoader.cfc. Here is the code I use to instantiate the classes I require for my manipulations.
<cfset javaLoader = server[application.myJavaLoaderKey]>
<cfset OPCPackage = javaLoader.create("org.apache.poi.openxml4j.opc.OPCPackage")>
<cfset dot_template_opc = OPCPackage.open("pathToDocxFileInstantiated")>
<cfset XWPFDocument = javaLoader.create("org.apache.poi.xwpf.usermodel.XWPFDocument")>
<cfset dot_template = XWPFDocument.init(dot_template_opc)>
<cfset XWPFParagraph = javaLoader.create("org.apache.poi.xwpf.usermodel.XWPFParagraph")>
<cfset XWPFTable = javaLoader.create("org.apache.poi.xwpf.usermodel.XWPFTable")>
<cfset XWPFRun = javaLoader.create("org.apache.poi.xwpf.usermodel.XWPFRun")>
<cfset CTP = javaLoader.create("org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP")>
<cfset CTRImpl = javaLoader.create("org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl")>
<cfset CTText = javaLoader.create("org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText")>
<cfset dot_output = "pathToNewDocxFile"><!--- Edited version of original --->
<cfset outputObject_dot = CreateObject("java","java.io.FiltOutputStream",
"java",
"java.io.FileOutputStream"
).Init(
CreateObject(
"java",
"java.io.File"
).Init(
dot_output
)>
Here is the relevant code from Application.cfc pertaining to JavaLoader.cfc. It is being held within the onApplicationStart() method.
<cfset var myJavaLoaderKey = "ABCDEF-01234567-9876543210-ABCDEF54321_javaloader">
<cfset var jarPaths = arrayNew(1)>
<!--- if the javaLoader was not created yet --->
<cfif NOT structKeyExists(server, myJavaLoaderKey)>
<!--- these are absolute paths to the POI jar files --->
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-examples-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-excelant-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-ooxml-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-ooxml-schemas-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/poi-scratchpad-3.10-FINAL-20140208.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/lib/commons-codec-1.5.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/lib/commons-logging-1.1.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/lib/junit-4.11.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/lib/log4j-1.2.13.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/ooxml-lib/dom4j-1.6.1.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/ooxml-lib/stax-api-1.0.1.jar")) >
<cfset arrayAppend( jarPaths, expandPath("../wwwroot/poi/ooxml-lib/xmlbeans-2.3.0.jar")) >
<cfif NOT structKeyExists(server, myJavaLoaderKey)>
<cflock name="#Hash(myJavaLoaderKey)#" type="exclusive" timeout="10">
<!--- create an instance of the JavaLoader and store it in the server scope --->
<cfset server[myJavaLoaderKey] = createObject("component", "javaloader.JavaLoader").init(loatPaths=jarPaths,loadColdFusionClassPath=true)>
</cflock>
</cfif>
<cfset application.myJavaLoaderKey = myJavaLoaderKey>
</cfif>
<cfscript>
_Thread = createObject("java", "java.lang.Thread");
currentClassloader = _Thread.currentThread().getContextClassLoader();
try { // Set the current thread's context class loader as Javaloader's classloader, so dom4j doesn't die _Thread.currentThread().setContextClassLoader(server[var.JLKey].getURLClassLoader());
}
catch(Any exc) {
rethrow;
}
finally { // We have to reset the classloader, due to thread pooling.
_Thread.currentThread().setContextClassLoader(currentClassloader);
}
</cfscript>
All this being said, I have NOT deleted the original .jars packaged with CF. I recently attempted to and was unable to, I'm sure I can if I try a little harder of course but, feel this should not be necessary.
I AM making a call to CreateObject to instantiate java.io.File and java.io.FileOutputStream. Does this somehow revert the instantiation of my XWPFDocument to CF's default class?
is this due to Apache POI .jars being updated and no longer supporting the setParagraph() method
Can you clarify "unable to access"? What is the exact exception and stack trace?
It is most likely the opposite. Rather than being deprecated or removed, that method was actually added in a newer version than the one you are using. As @Gagravarr mentioned, CF ships with an old version of POI. You did not tell us your CF version, but CF10 is bundled with POI "3.6-beta1". The live API usually points to the latest stable version, currently "3.10 Final". Obviously 3.10 may include new methods and/or classes that will not be available when using earlier versions.
There are several options for using a newer version of POI.
{cf_root}\lib
with newer versions. Then restart the CF server (required). Note: I have not done this personally, so I do not know if doing so will break other featuresthis.javaSettings
, in your Application.cfc to load newer versions of the POI jars.Side note, the Word API is not as mature as the one for Excel, so keep that in mind.
Update 1:
How did you determine the object "does not have a setParagraph" method? If you did a cfdump
, and did not see the setParagraph()
method listed, then you probably are not loading the newer version of the class. Can you please post your code showing how you instantiate the JavaLoader and create the
XWPFDocument
object?
Without knowing more, my guess is maybe you accidentally used createObject()
somewhere. So you are still getting the older version of the class, not the newer one. ie:
//this loads the older version in cf_root/lib
createObject("java", "path.to.Class");
// this loads the newer version in JavaLoader paths
javaLoader.create("path.to.Class");
Update 2:
Interesting. The code is loading the older version, but not for the reason above. (See Debugging Tip: Identifying Which Jar file a class was loaded from in ColdFusion MX)
I believe cause of the problem is that the JavaLoder paths parameter is misspelled: loatPaths
instead of loadPaths
. So it defaults to an empty array. The result being you are not actually loading any of the new jars. Since loadColdFusionClassPath=true
you end up loading the old version instead.
Side note, a simpler way to generate a list of paths in CF9 is to use DirectoryList()
. That function will allow you to grab all of the paths in one shot. That said, one very important note. POI uses the dom4j library, which is known for class loading issues. Loading two versions of the jar will cause problems - even with the JavaLoader. So be sure to remove the /poi/ooxml-lib/dom4j-1.6.1.jar
file first. (That should also remove the need to swap out the currentClassloader
).
jarPaths = DirectoryList(expandPath("/poi/"), true, "path", "*.jar")