Jxls是一个java开源项目的名称。它按照自定义的excel模板来生成excel文件。excel模板也是一个xls文件,上面有一些jxls定义的标签。
Leader Bruise最近给了我一个任务:把jxls化为"nxls",也就是把它移植到.net平台上。
经过一段时间的了解,我发现把java代码移植到.net不外乎以下三种方法:
- 手工翻译源代码。
- 使用M$的JLCA(Microsoft Java Language Conversion Assistant 3.0)来翻译源代码。
- 使用ikvm翻译目标代码。
这三种方法各有各的优点,也各有各的问题。
手工翻译源代码的最大优点是彻底,可以保证翻译的质量。缺点是工程非常庞大,jxls本身就有100万字节以上的代码(包括注释),而且还大量引用了其它开源项目(下文会给出其依赖图),如果要转换的话必须把它所依赖的所有项目都转换。(你总不能叫.net去引用某个jar包吧?)
用M$的JLCA可以把项目里大多数代码翻译成C#,翻译质量还不错,但也不能100%地转换,最后还是要手工修改,估计代码量还是太大。
ikvm比较特别,它实现的是中间码的转换,形象地说就是把.jar转换成.dll,由于转换后的类库立即可用,因此这绝对是代价最低的办法。但也存在一些问题:
- ikvm有bug,目前最常见的问题转换后的程序会抛出类初始化失败的异常,期待其将来的版本能够修正这些问题。
- 使用转换后的类库的程序必需引用ikvm的dll库。主要是指IKVM.Hybrid.GNU.Classpath.OpenJDK.dll和IKVM.Runtime.dll,平白地增加了20多M,不爽,而且还不能放进GAC(ikvm-0.34.0.2版可以,但它的RPWT好像比较严重)
- 接口不干净。尽管ikvm已经尽力做了一些类型的映射,比如将java.lang.String映射到System.String,但它对一些较复杂的类(比如说:File类)是无能为力的,而这些类常常会出现在用户使用的接口上,这使得用户使用该接口变得麻烦。可以考虑手工写一些Adapter来解决。
- 缺乏源代码和相关文档,用户不懂得怎么调用。当然,也可以用reflector等反编译工具来得到源代码。
经过以上的分析之后,我决定按以下步骤来进行转换:
第一步:找出所有的jar包的依赖关系,从而明确工作目标。
第二步:使用ikvm将所有相关的jar包编译成dll。
第三步:使用JLCA将所有的示例代码转换成C#源代码,用于测试转换后的类库,可能需要修改类库里的少量代码。
第四步:假如有时间,再逐个将各个dll中间码类库改成真正的C#源代码类库。
附:经过今日的一番努力,以及Maven的帮助,终于了解jxls-core及其所依赖的各类库的依赖关系,并画出“依赖树”如下:
再附:最近手风一直不太顺,转换后的dll常常抛出一些莫名其妙的异常,首先是在digester里边的org.apache.commons.digester.ObjectCreateRule.begin(Attribute)处,使用语句“Class clazz = digester.getClassLoader().loadClass(realClassName); ”会抛出ClassNotFoundException,其中realClassName的值是“net.sf.jxls.tag.ForEachTag ”,我把该语句改成“ Class clazz = java.lang.Thread.currentThread().getContextClassLoader().loadClass(realClassName);
”(也就是说,换了一个ClassLoader)可以解决。
改完后又抛出了一个RuntimeException:
StackTrace
未处理 java.lang.RuntimeException
Message="Can't parse an expression departments"
Source="myjxls-core-0.9.5"
StackTrace:
在 net.sf.jxls.tag.ForEachTag.parseItemsProperty()
在 net.sf.jxls.tag.ForEachTag.init(TagContext tagContext)
在 net.sf.jxls.parser.CellParser.parseTag(String , Block , Map , Boolean )
在 net.sf.jxls.parser.CellParser.parseCellValue(Map )
在 net.sf.jxls.parser.CellParser.parseCell(Map beans)
在 net.sf.jxls.transformer.SheetTransformer.parseCells(Sheet , HSSFRow , Int16 , Int16 , Map )
在 net.sf.jxls.transformer.SheetTransformer.parseRow(Sheet , HSSFRow , Map )
在 net.sf.jxls.transformer.SheetTransformer.transformSheet(WorkbookTransformationController , Sheet , Map )
在 net.sf.jxls.transformer.XLSTransformer.transformWorkbook(HSSFWorkbook hssfWorkbook, Map beanParams)
在 net.sf.jxls.transformer.XLSTransformer.transformXLS(InputStream is, Map beanParams)
在 net.sf.jxls.transformer.XLSTransformer.transformXLS(String srcFilePath, Map beanParams, String destFilePath)
在 net.sf.jxls.sample.BasicTagSample.Main(String[] args) 位置 F:\acumon\job\nxls\nxls.net\main\java\net\sf\jxls\testsample\BasicTagSample.cs:行号 65
在 System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
在 System.Threading.ThreadHelper.ThreadStart()
posted on 2007-08-16 21:10
踏雪赤兔 阅读(2815)
评论(5) 编辑 收藏 引用