on 2024 Jun 12 4:04 PM
If you use the java libraries on linux with an OpenJDK (e.g. Eclipse Adoptium) and export a report as PDF you'll get a NullPointerException.
One workaround is to copy all needed fonts in the openjdk into jre/lib/fonts or lib/fonts (depending on the version) - but you have to do this manually after every java update.
This happens on alle linux-systems I've tested so far (Ubuntu, Debian, RedHat, Oracle, ...)
All distros have already a folder with fonts and if also Java knows the installed fonts.
for (final String _f
: GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames())
System.out.println(_f);
IMO this is a bug or hardcoded path somewhere in the crystal reports libraries.
Or does anybody know a fix for this problem? E.g. setting a system-property to the font-directory to use, call some kind of method to configure the path or do some magic on the system itself?
Unfortunately using symlinks also do not work (neither for files or folders) - afaik you have to copy all ttf-Files in the mentioned folder.
This is the Exception you get with a default OpenJDK:
detected an exception: java.lang.NullPointerException
at com.crystaldecisions.reports.exporters.format.page.pdf.fontembedding.opentype.tables.OS2Table.<init>(SourceFile:108)
at com.crystaldecisions.reports.exporters.format.page.pdf.fontembedding.FontEmbeddingSession.if(SourceFile:116)
at com.crystaldecisions.reports.exporters.format.page.pdf.fontembedding.FontEmbeddingSession.a(SourceFile:104)
at com.crystaldecisions.reports.exporters.format.page.pdf.pdflib.r.if(SourceFile:594)
at com.crystaldecisions.reports.exporters.format.page.pdf.pdflib.r.a(SourceFile:424)
at com.crystaldecisions.reports.exporters.format.page.pdf.pdflib.PdfDocumentManager.a(SourceFile:337)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.a(SourceFile:1584)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.a(SourceFile:1492)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.a(SourceFile:780)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.a(SourceFile:729)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.a(SourceFile:683)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.a.if(SourceFile:633)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.d.a(SourceFile:1951)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.d.a(SourceFile:447)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.d.byte(SourceFile:323)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.d.a(SourceFile:303)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.d.a(SourceFile:283)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.b.a(SourceFile:217)
at com.crystaldecisions.reports.exporters.format.page.pdf.dom.PdfAdvancedDocumentModeller.a(SourceFile:177)
at com.crystaldecisions.reports.exporters.page.pdf.AdobePDFExporter.a(SourceFile:252)
at com.crystaldecisions.reports.exporters.page.pdf.AdobePDFExporter.processFormattedContent(SourceFile:200)
at com.crystaldecisions.reports.formatter.export2.a.a(SourceFile:105)
at com.crystaldecisions.reports.formatter.export2.a.a(SourceFile:253)
at com.crystaldecisions.reports.formatter.export2.ExportSupervisorEx.if(SourceFile:647)
at com.crystaldecisions.reports.formatter.export2.ExportSupervisorEx.a(SourceFile:597)
at com.businessobjects.reports.sdk.requesthandler.ReportViewingRequestHandler.a(SourceFile:641)
at com.businessobjects.reports.sdk.requesthandler.ReportViewingRequestHandler.int(SourceFile:666)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.do(SourceFile:1944)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.if(SourceFile:661)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.a(SourceFile:167)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter$2.a(SourceFile:529)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter$2.call(SourceFile:526)
at com.crystaldecisions.reports.common.ThreadGuard.syncExecute(SourceFile:102)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.for(SourceFile:525)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.int(SourceFile:424)
at com.businessobjects.reports.sdk.JRCCommunicationAdapter.request(SourceFile:352)
at com.businessobjects.sdk.erom.jrc.a.a(SourceFile:54)
at com.businessobjects.sdk.erom.jrc.a.execute(SourceFile:67)
at com.crystaldecisions.proxy.remoteagent.RemoteAgent$a.execute(SourceFile:716)
at com.crystaldecisions.proxy.remoteagent.CommunicationChannel.a(SourceFile:125)
at com.crystaldecisions.proxy.remoteagent.RemoteAgent.a(SourceFile:537)
at com.crystaldecisions.sdk.occa.report.application.dt.a(SourceFile:186)
at com.crystaldecisions.sdk.occa.report.application.ReportSource.a(SourceFile:1558)
at com.crystaldecisions.sdk.occa.report.application.ReportSource.a(SourceFile:337)
at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.if(SourceFile:224)
at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.export(SourceFile:206)
at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.export(SourceFile:184)
at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.export(SourceFile:167)
Yes, the directory where Crystal is taking the fonts from seems to be hardcoded to java.home\lib\fonts.
I found the following snippet in the source code of the fontembedding.class of Cystal Reports.
public static Map<String, OpenTypeFontFamily> if() {
StringBuilder stringBuilder = new StringBuilder();
String string = System.getProperty("java.home");
if (!string.endsWith(File.separator)) {
stringBuilder.append(string).append(File.separator).append("lib").append(File.separator).append("fonts");
} else {
stringBuilder.append(string).append("lib").append(File.separator).append("fonts");
}
Map<String, OpenTypeFontFamily> map = b.a(new File(stringBuilder.toString()));
return map;
}
Such hardcoded paths always brings the risk for the reports not to work properly when deployed on a new machine that might have those fonts installed in other directories like /usr/share/fonts/. Nowadays JRE will pick the fonts automatically. This should not be hardcoded from my point of view.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Martin,
thank you for the hint - I've already checked the stacktrace multiple times but with your hint I found a much better workaround to this issue.
The class contains also a method do() where
System.getProperty("SystemFontPath", "C:\\Windows\\Fonts");
is called.
So I set
-DSytemFontPath=/usr/share/fonts/
but unfortunately that didn't help.
From earlier tests I know that the search is not recursive and therefore I've tried an existing folder that contains ttf-Files.
-DSystemFontPath=/usr/share/fonts/truetype/dejavu/
and with this path I don't get a NullPointerException even if the java.home/lib/fonts does not exist. 👍👍👍👍👍👍
Now I've added a configuration to our app to specify font-directories, collect all folders containing ttf-Files and set the system-property programatically.
Thank you very much for pointing me in this direction.
[edit]
Maybe I did something wrong - I have the NPE again. Currently I need at least one ttf-File in java.home/lib.fonts
But fonts are also loaded from SystemFontPath
[/edit]
[edit2]
I only get the NullPointerException if the reports uses a fonts that is not available in SystemFontPath.
An untouched JRE/JDK is much more better than a rare NullPointerException that can be fixed with adding the correct folders to the SystemFontPath
[/edit2]
A more rubust solution from Crystal Reports would be better of course but for now this is a workaround I can live with it.
User | Count |
---|---|
68 | |
10 | |
10 | |
7 | |
7 | |
6 | |
6 | |
5 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.