Bridging Java to .NET or how to lose several days of your life

I’ve been spending time for the past three weeks on and off trying to figure out how to use old Java code in one of our .NET projects. A goal for a couple of upcoming clients is to better facilitate the generation of tax and various government forms. With the many thousands of forms we need to support we didn’t want to design and maintain these forms in-house. For a solution we turned to our primary dead tree form provider Nelco.

Nelco provides a PDF form package but unfortunately the PDFs are not AcroForm compatible. You have to use their XML/PDF form merging software solution. More unfortunately their solution is a 10 year old Java package SDK with no source code. I have nothing against Java but here at TempWorks we settled on .NET many years ago and I am not a fan of mixing development platforms. For the past 9 years .NET has provided everything I need to get my job done. So here is my problem, how to get this Java package to work with our .NET code without any weird hacks and make it easy for future TempWorks .NET developers to maintain.

I spent a few days trying various packages without much luck. A few worked fine but they were expensive from a royalty perspective or were more cumbersome then just using Java and writing a web service for communication. Finally I came across an open source solution called IKVM.NET. The cool thing with this solution is you can use IKVM to convert compiled Java code (classes or jar files) and convert it to .NET compiled assemblies. After a few days trying to find the magic IKVM’s command line recipe and fighting with Java class paths, success!

Example Java code from Nelco’s SDK

// This code does the merging of an xml file and a pdf file.  The fields 
// are loaded from the Xml document by the FormBean "utility" into the 
// FormFields object named "inputFields".  The fields are merged into an 
// existing pdf file specified by the variable "pdfFile" by the PDFMerge 
// object named "pd".  The resulting pdf object with the merged xml fields 
// is the Pdf object named "pdf".  An new FileOutputStream is created 
// using the output pdf name and then the function writeToStream is called 
// to write the merged pdf document to disk.
public Pdf PdfFileMergeXmlFile(String xmlInputFile, String pdfFile) {
  // The following code just tweaks the necessary file names.
  xmlInputFile = xmlInputFile + ".xml";
  String pdfOutputFile = pdfFile + "_1_OUT.pdf";
  pdfFile = pdfFile + ".pdf";
  // Now create the necessary Pdf and FormFields objects.
  Pdf pdf = null;
  FormFields inputFields = null;
  // The following string and object are used to read the XML and
  // create a FormField object.
  String xmlbuf = null;
  FormBean utility = new FormBean();
  // for purposes of this example, default data is read from a file (xmlInputFile)
  // and merged with the PDF represented by pdfFile.
  try {
    // The following block of code reads the input data/fields from the XML
    // data file stored on disk.
    xmlbuf = utility.getXML(new File(xmlInputFile));
    utility.setInputFieldsXML(xmlbuf);
    inputFields = utility.getFormFieldsInput();
    System.out.println("- Loaded input data from: " + xmlInputFile);
    // We use the PDFMerge object to merge a FormFields object and a Pdf object.
    PDFMerge pd = new PDFMerge();
    // So, here we are making the call to do the merge.
    pdf = pd.merge(pdfFile, inputFields);
    System.out.println("- Data successfully merged with " + pdfFile);
    // Here we are writing the PDF file out to disk.  First, we get a new
    // FileOutputStream with the desired file name.  Next, we call the Pdf's
    // writeToStream method to write out the Pdf.
    FileOutputStream fos = new FileOutputStream(pdfOutputFile);    
    pdf.writeToStream(fos);
    System.out.println("- Wrote new PDF file " + pdfOutputFile + " successfully");
  } catch (Exception ex) {
    ex.printStackTrace();
  }
  return pdf;
}


The resulting .NET assembly generated by IKVM in Reflector.

image



My C# console application using the above Java example code.

using System;
using com.etymon.pj;
using com.nelco.form;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xmlInputFile = @"E:\Temp\Nelco\pdfdemo\79411.xml";
            string pdfFile = @"E:\Temp\Nelco\pdfdemo\79411.pdf";
            string pdfOutputFile = @"e:\temp\79411_OUT.pdf";
            var pdf = PdfFileMergeXmlFile(xmlInputFile, pdfFile, pdfOutputFile);
            Console.ReadLine();
        }
        private static Pdf PdfFileMergeXmlFile(String xmlInputFile, String pdfFile, String pdfOutputFile)
        {
            Pdf pdf = null;
            FormFields inputFields = null;
            string xmlbuf = null;
            FormBean utility = new FormBean();
            xmlbuf = utility.getXML(new java.io.File(xmlInputFile));
            utility.setInputFieldsXML(xmlbuf);
            inputFields = utility.getFormFieldsInput();
            Console.WriteLine("- Loaded input data from: " + xmlInputFile);
            PDFMerge pd = new PDFMerge();
            java.io.FileOutputStream fos = new java.io.FileOutputStream(pdfOutputFile);
            pd.merge(pdfFile, inputFields, fos);
            Console.WriteLine("- Wrote new PDF file = " + pdfOutputFile + " successfully");
            return pdf;
        }
    }
}


WOOT!

image



Kudos to the main guy behind IKVM.NET, you saved me a bunch of work.

0 comments:

Post a Comment