我转发了一项要求,将动态RTF文档转换为PDF,在转换前填充RTF中的所有属性。
按照此blog post中的确切示例,我在运行应用程序时遇到了NullPointerException
。
注意:我知道iText上的RTF文档支持已经abandoned,但它已被客户端使用。
确切的堆栈跟踪:
Exception in thread "main" java.lang.NullPointerException
at com.lowagie.text.rtf.parser.destinations.RtfDestinationFontTable.importSystemFonts(RtfDestinationFontTable.java:571)
at com.lowagie.text.rtf.parser.destinations.RtfDestinationFontTable.init(RtfDestinationFontTable.java:206)
at com.lowagie.text.rtf.parser.destinations.RtfDestinationFontTable.setParser(RtfDestinationFontTable.java:190)
at com.lowagie.text.rtf.parser.destinations.RtfDestinationMgr.addDestination(RtfDestinationMgr.java:184)
at com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordHandler.<init>(RtfCtrlWordHandler.java:175)
at com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordMap.<init>(RtfCtrlWordMap.java:607)
at com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordMgr.<init>(RtfCtrlWordMgr.java:93)
at com.lowagie.text.rtf.parser.RtfParser.init(RtfParser.java:655)
at com.lowagie.text.rtf.parser.RtfParser.convertRtfDocument(RtfParser.java:551)
at za.co.sindi.utils.Prints.printToPDFWithIText(Prints.java:114)
at za.co.sindi.utils.Prints.main(Prints.java:150)
源代码示例:
public static void printToPDFWithIText() {
InputStream input = null;
OutputStream output = null;
Document document = null;
try {
input = new BufferedInputStream(new FileInputStream(new File("C:/testPDF.rtf")));
output = new BufferedOutputStream(new FileOutputStream(new File("C:/testPDF_" + System.nanoTime() + ".pdf")));
document = new Document();
PdfWriter.getInstance(document, output);
document.open();
RtfParser parser = new RtfParser(null);
parser.convertRtfDocument(input, document); //NullPointerException is here (line 114)
document.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (output != null) {
try {
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// if (document != null && document.isOpen()) {
// document.close();
// }
}
}
我该如何解决这个问题?
答案 0 :(得分:4)
罪魁祸首是com.lowagie.text.rtf.parser.destinations.RtfDestinationFontTable
班上的以下实施:
private Properties getEnvironmentVariables() throws Throwable {
Properties environmentVariables = new Properties();
String operatingSystem = System.getProperty("os.name").toLowerCase();
Runtime runtime = Runtime.getRuntime();
Process process = null;
if (operatingSystem.indexOf("windows 95") > -1
|| operatingSystem.indexOf("windows 98") > -1
|| operatingSystem.indexOf("me") > -1) {
process = runtime.exec("command.com /c set");
} else if ((operatingSystem.indexOf("nt") > -1)
|| (operatingSystem.indexOf("windows 2000") > -1)
|| (operatingSystem.indexOf("windows xp") > -1)
|| (operatingSystem.indexOf("windows 2003") > -1)
|| (operatingSystem.indexOf("windows vista") > -1)) {
process = runtime.exec("cmd.exe /c set");
} else {
process = runtime.exec("env");
}
BufferedReader environmentStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
String inputLine = "";
int idx = -1;
while ((inputLine = environmentStream.readLine()) != null) {
idx = inputLine.indexOf('=');
inputLine.substring(idx + 1));
}
}
显然,开发人员检查了从Windows 95到Windows Vista的Windows操作系统。他/她忘记检查Windows 7和Windows 8环境。
System.getProperty("os.name");
在我的开发工作站上返回Windows 7
,因此Runtime
尝试调用 <进程env
进程在Windows环境中。由于这会抛出Throwable
,因此会出现以下情况:
private void importSystemFonts() {
Properties pr = null;
try {
pr = getEnvironmentVariables();
} catch (Throwable e) {
}
String systemRoot = pr.getProperty("SystemRoot");
Runtime runtime = Runtime.getRuntime();
String fileSeperator = System.getProperty("file.separator");
int r = FontFactory.registerDirectory(systemRoot + fileSeperator + "fonts");
}
如您所见,pr
字段最初为null
。现在,有罪的方法(已经提到过)引发了一个例外,importSystemFonts
没有做任何事情来迎合它,尽管它抓住了它。因此pr
仍为null
。
行String systemRoot = pr.getProperty("SystemRoot");
现在会抛出NullPointerException
。
我们如何解决?
在运行你的程序之前,你将不得不作弊:愚弄它不是Windows 7或更高版本的库。就我而言,我将其设置为Windows Vista
。
在执行代码之前,必须:
System.setProperty("os.name", "Windows Vista");
现在,运行您的代码,您将看到异常消失。
注意:看到此课程已被放弃,请自行承担风险。如果你还在使用这个版本的iText,我发布这个是为了帮助别人。
答案 1 :(得分:0)
版本1:
如果你构建了rft.jar,你还可以再添加一个条件到上面提到的:
|| (operatingSystem.indexOf("windows 7") > -1))
(因为这只决定调用(process = runtime.exec("cmd.exe /c set");)
)
更新:(版本2)
更好的实施方式是:
//1. delete method 'getEnvironmentVariables(...)' completely
//2. import system fonts like this:
private void importSystemFonts() {
String systemRoot = System.getenv("SystemRoot");
String fileSeperator = System.getProperty("file.separator");
FontFactory.registerDirectory(systemRoot + fileSeperator + "fonts");
}