2
votes

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?

1
What is your CF server version?Sergey Babrenok
IIRC, ColdFusion ships some rather old POI jars as standard. Did you make sure you properly upgraded POI, including removing the old CF supplied jars?Gagravarr
Hello all, I am currently running CF9. I am NOT removing CF supplied .jars as I am loading the objects using JavaLoader.cfc.Synesthesia

1 Answers

2
votes

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.

  • Overwrite the existing POI jars in {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 features
  • For CF9 or earlier, use the JavaLoader.cfc to run the newer version in parallel.
  • As of CF10, there is a rip of the JavaLoader.cfc baked in. So you can use this.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")