Reputation: 345
I am trying to convert the code below to Coldfusion. I am currently stuck on how to convert the "Transformer transformer = TransformerFactory.newInstance().newTransformer()" line to Coldfusion. Can anyone help convert this code?
The error message I get when using transformer = loader.create("javax.xml.transform.TransformerFactory").newInstance().newTransformer();
Error casting an object of type org.apache.xalan.processor.TransformerFactoryImpl cannot be cast to javax.xml.transform.TransformerFactory to an incompatible type. This usually indicates a programming error in Java, although it could also mean you have tried to use a foreign object in a different way than it was designed. org.apache.xalan.processor.TransformerFactoryImpl cannot be cast to javax.xml.transform.TransformerFactory
Document svgXmlDoc = ...
File svgFile = File.createTempFile("graphic-", ".svg");
Transformer transformer = TransformerFactory.newInstance().newTransformer();
DOMSource source2 = new DOMSource(svgXmlDoc);
FileOutputStream fOut = new FileOutputStream(svgFile);
try { transformer.transform(source2, new StreamResult(fOut)); }
finally { fOut.close(); }
// Convert the SVG into PDF
File outputFile = File.createTempFile("result-", ".pdf");
SVGConverter converter = new SVGConverter();
converter.setDestinationType(DestinationType.PDF);
converter.setSources(new String[] { svgFile.toString() });
converter.setDst(outputFile);
converter.execute();
Here is my code so far.
<cfscript>
paths = arrayNew(1);
paths[1] = expandPath("jar\avalon-framework-impl-4.2.0.jar");
paths[2] = expandPath("jar\batik-all-1.7.jar");
paths[3] = expandPath("jar\commons-io-1.3.1.jar");
paths[4] = expandPath("jar\commons-logging-1.0.4.jar");
paths[5] = expandPath("jar\fop-0.9.5.jar");
paths[6] = expandPath("jar\apache-log4j-1.2.15.jar");
paths[7] = expandPath("jar\xml-apis-ext.jar");
paths[8] = expandPath("jar\xmlgraphics-commons-1.3.1.jar");
paths[8] = expandPath("jar\javax.xml-1.3.4.jar");
loader = createObject("component", "javaloader.JavaLoader").init(paths);
destinationtype = loader.create("org.apache.batik.apps.rasterizer.DestinationType");
svgconverter = loader.create("org.apache.batik.apps.rasterizer.SVGConverter");
// SVG available as a DOM object (created programatically by my program)
svgXmlDoc = '<svg><text y="3.58in" x="1.5000in" id="fooddesc1" text-anchor="start" alignment-baseline="baseline">This is a test.</text></svg>';
// Save this SVG into a file (required by SVG -> PDF transformation process)
f = loader.create("java.io.File");
svgFile = f.createTempFile("graphic-", ".svg");
transformer = loader.create("javax.xml.transform.TransformerFactory");
source2 = loader.create("javax.xml.transform.dom.DOMSource").init(svgXmlDoc);
fOut = loader.create("java.io.FileOutputStream").init(svgFile);
</cfscript>
Upvotes: 0
Views: 707
Reputation: 28873
Looks like the code you are translating is from this thread. I would suggest using the accepted answer instead. It is a bit simpler. However, you do not need to use the JavaLoader since you are running CF11. Starting from CF10, a rip of Mark Mandel's JavaLoader.cfc is baked into CF. Applications can load jars dynamically using this.javaSettings in the Application.cfc. The simplest option is to stick all of the jars in a separate directory, and point to that path in your application settings. Then you can load any of the classes with createObject().
this.javaSettings = {LoadPaths = [ "/path/to/jars_folder/" ]};
Example:
transcoder = createObject("java", "org.apache.fop.svg.PDFTranscoder").init();
// load text into a reader and create the source input
svgText = '<svg xmlns="http://www.w3.org/2000/svg"><text y="3.58in" x="1.5000in" id="fooddesc1" text-anchor="start" alignment-baseline="baseline">This is a test.</text></svg>';
reader = createObject("java", "java.io.StringReader").init(svgText);
input = createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(reader);
// for demo purposes, create a unique file name
outPath = ExpandPath("./"& createUUID() &".pdf");
fos = createObject("java", "java.io.FileOutputStream").init(outPath);
output = createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(fos);
transcoder.transcode(input, output);
// ALWAYS close the stream
fos.close();
The simple example above was tested with the following jars under CF10, so YMMV.
Original Exception
Error casting an object of type org.apache.xalan.processor.TransformerFactoryImpl cannot be cast to javax.xml.transform.TransformerFactory
I am not entirely sure what was causing the ClassCastException. I suspect it is some sort of a class loader issue. CF is already bundled with several of the libraries you are loading. At least one of the core jars contains another version of the TransformerFactory
. Under CF10, the error goes away if you omit the javax.xml-1.3.4.jar (and commons-logging-1.0.4.jar). So somehow the various pieces are not playing well together under the custom class loader. Hence why things blow up when you call TransformerFactory.newInstance()
. However, since you do not really need that class anyway, I did not look into it further...
Update:
FWIW, the error was definitely caused by a class loader conflict. The original code works fine if you omit javax.xml-1.3.4.jar (and commons-logging-1.0.4.jar).
If you look at the source for TransformerFactory.newInstance() you can see a call to FactoryFinder.find() which references different class loaders depending on the conditions. Since CF already includes the javax.xml.* package, I suspect some of the objects are being created by CF's class loader ie org.apache.xalan.processor.TransformerFactoryImpl
, while others ie TransformerFactory
are created by a different class loader ie JavaLoader.
Class loaders are notoriously finicky. You have to follow certain rules or the objects created by one class loader will NOT be recognized by another - not even if they represent the exact same class. That seems to be what is happening here. You could probably fiddle with the parent or context class loader to get around it, but in this case it is simpler to just omit the javax.xml-1.3.4.jar.
Now having said all that ... I do not think you need the TransformerFactory code at all. It sounds like you already have a valid SVG string. Simply simply save it to a file with FileWrite()
and move on with the rest of the code.
Upvotes: 1