I'm using Java 11 Corretto + Spring Boot with Apache POI but I'm facing issues when using on AWS Lambda. Works fine if I run as "normal" API but fails when running servless in a AWS lambda.
try (ByteArrayOutputStream out = new ByteArrayOutputStream(); SXSSFWorkbook workbook = new SXSSFWorkbook(1000)) {
SXSSFSheet sheet = workbook.createSheet("test"); //error here!!
} ...
Caused by: java.lang.Error: Probable fatal error: No physical fonts found. at java.desktop/sun.font.SunFontManager.lambda$getDefaultPhysicalFont$0(Unknown Source) at java.base/java.util.Optional.orElseThrow(Unknown Source) at java.desktop/sun.font.SunFontManager.getDefaultPhysicalFont(Unknown Source) at java.desktop/sun.font.CompositeFont.doDeferredInitialisation(Unknown Source) at java.desktop/sun.font.CompositeFont.getSlotFont(Unknown Source) at java.desktop/sun.font.CompositeGlyphMapper.initMapper(Unknown Source) at java.desktop/sun.font.CompositeGlyphMapper.(Unknown Source) at java.desktop/sun.font.CompositeFont.getMapper(Unknown Source) at java.desktop/sun.font.CompositeFont.canDisplay(Unknown Source) at java.desktop/java.awt.Font.canDisplayUpTo(Unknown Source) at java.desktop/java.awt.font.TextLayout.singleFont(Unknown Source) at java.desktop/java.awt.font.TextLayout.(Unknown Source) at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:285) at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.(AutoSizeColumnTracker.java:117) at org.apache.poi.xssf.streaming.SXSSFSheet.(SXSSFSheet.java:84) at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:705) at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:724)
I tried to create a fix to the fonts but I have no idea how to proceed
@PostConstruct
public void loadFonts() {
URL configURL = getClass().getClassLoader().getResource("fontconfig.properties");
String path = configURL != null ? configURL.getPath() : null;
Properties props = System.getProperties();
LOGGER.info("Loading font config file: {}", path);
props.put("sun.awt.fontconfig", path);
String[] fonts;
try {
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
} catch (Throwable ex) {
LOGGER.warn("Reloading Fonts");
}
try {
fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (String font : fonts) {
LOGGER.info("Available Font: {}", font);
}
} catch (Throwable ex) {
LOGGER.error("Could not load Fonts");
}
}
Config file:
version=1
sequence.allfonts=default
When running on AWS Lambda it outputs some fonts to the logs so I don't understand why I get that error:
2022-05-31 16:00:14 INFO Starting Lambda Container Handler 2022-05-31 16:00:18 INFO Loading font config file: /var/task/fontconfig.properties 2022-05-31 16:00:18 INFO Available Font: Dialog 2022-05-31 16:00:18 INFO Available Font: DialogInput 2022-05-31 16:00:18 INFO Available Font: Monospaced 2022-05-31 16:00:18 INFO Available Font: SansSerif 2022-05-31 16:00:18 INFO Available Font: Serif
Any idea how to add physical fonts and why can't the POI use the available fonts that output to the logs?
EDIT: I also tried to run as headless but I get the same error:
`props.setProperty("java.awt.headless", "true");`
Any idea how to add physical fonts
The Oracle JDK product from Oracle stopped bundling fonts as of Java 11.
The OpenJDK project does not bundle fonts, at least not in recent versions.
The Corretto JDK from Amazon product is based on OpenJDK codebase. Given your report, apparently they do not bundle fonts.
You must choose to:
I know of at least one such vendor: Azul Systems bundles fonts with their Azul Platform Core commercial product.
There may be other such vendors that I’m not aware of. Many vendors provide JDK binaries and installers. These vendors include Adoptium, SAP, BellSoft, Microsoft, Azul Systems, Amazon, Oracle, Red Hat/IBM, Pivotal, and more.
why can't the POI use the available fonts that output to the logs
The fonts you listed in your logs are logical fonts, not physical fonts. The distinction is clearly documented in the Javadoc for the Font
class.
To use a logical font name, you must have some backing physical font. If no fonts exist within your app, within your JDK, or within your host OS, then the logical fonts cannot work.
Regarding making fonts available in AWS Lambda, perhaps these two pages might help. (Thanks to jarmod for the links.)
The basic idea is to create a /fonts
folder within your package. Incude a fonts.conf
file within, with XML configuration elements. Place your bundled fonts files alongside that config file.
Be aware that some fonts are commercial, with a license that requires a fee. When bundling/deploying fonts, be sure to verify that you are meeting the terms of their license.