Java调用PlantUML生成UML图时报IllegalAccessError错误
问题描述
使用Java编写代码生成简单PlantUML图形时,程序运行持续抛出错误,相关实现代码如下:
实现代码
public class PlantUMLDemoMain { public static void main(String[] args) throws Exception { generateFromStringSource(new File("from-string.png")); generateFromApi(new File("from-api.png")); } private static void generateFromApi(File file) throws IOException { // 1. setup: SequenceDiagramFactory f = new SequenceDiagramFactory(); SequenceDiagram diagram = f.createEmptyDiagram(); // 2. Build the diagram: // "Bob -> Alice : hello" // See net.sourceforge.plantuml.sequencediagram.command.CommandArrow#executeArg Display bobD = Display.getWithNewlines("Bob"); Participant bobP = diagram.getOrCreateParticipant("Bob", bobD); Display aliceD = Display.getWithNewlines("Alice"); Participant aliceP = diagram.getOrCreateParticipant("Alice", aliceD); Display label = Display.getWithNewlines("hello"); ArrowConfiguration config = ArrowConfiguration.withDirectionNormal(); Message msg = new Message(bobP, aliceP, label, config, diagram.getNextMessageNumber()); checkState(null == diagram.addMessage(msg)); // 3. Output the diagram // See net.sourceforge.plantuml.SourceStringReader#generateImage diagram.makeDiagramReady(); checkState(1 == diagram.getNbImages()); try (OutputStream os = new FileOutputStream(file)) { ImageData imageData = diagram.exportDiagram(os, 0, new FileFormatOption(FileFormat.PNG)); System.out.println("generateFromApi: " + diagram.getDescription().getDescription()); } } private static void generateFromStringSource(File file) throws IOException { String source = "@startuml\n"; source += "Bob -> Alice : hello\n"; source += "@enduml\n"; StringBuffer stringBuffer = new StringBuffer(); SourceStringReader reader = new SourceStringReader(source); // Write the first image to "png" String desc = reader.generateImage(file); // Return a null string if no generation System.out.println("generateFromStringSource: " + desc); } }
运行异常信息
Error: Exception in thread "main" java.lang.IllegalAccessError: class net.sourceforge.plantuml.png.PngIOMetadata (in unnamed module @0x9597028) cannot access class com.sun.imageio.plugins.png.PNGMetadata (in module java.desktop) because module java.desktop does not export com.sun.imageio.plugins.png to unnamed module @0x9597028 at net.sourceforge.plantuml.png.PngIOMetadata.writeWithMetadata(PngIOMetadata.java:60) at net.sourceforge.plantuml.png.PngIO.write(PngIO.java:86) at net.sourceforge.plantuml.png.PngIO.write(PngIO.java:80) at net.sourceforge.plantuml.ugraphic.g2d.UGraphicG2d.writeImageTOBEMOVED(UGraphicG2d.java:219) at net.sourceforge.plantuml.ugraphic.ImageBuilder.writeImageInternal(ImageBuilder.java:249) at net.sourceforge.plantuml.ugraphic.ImageBuilder.writeImageTOBEMOVED(ImageBuilder.java:171) at net.sourceforge.plantuml.sequencediagram.graphic.SequenceDiagramFileMakerPuma2.createOne(SequenceDiagramFileMakerPuma2.java:234) at net.sourceforge.plantuml.sequencediagram.SequenceDiagram.exportDiagramInternal(SequenceDiagram.java:222) at net.sourceforge.plantuml.UmlDiagram.exportDiagramNow(UmlDiagram.java:236) at net.sourceforge.plantuml.AbstractPSystem.exportDiagram(AbstractPSystem.java:127) at net.sourceforge.plantuml.SourceStringReader.generateImage(SourceStringReader.java:124) at net.sourceforge.plantuml.SourceStringReader.generateImage(SourceStringReader.java:111) at net.sourceforge.plantuml.SourceStringReader.generateImage(SourceStringReader.java:101) at scr.graphviz.sk.PlantUMLDemoMain.generateFromStringSource(PlantUMLDemoMain.java:66) at scr.graphviz.sk.PlantUMLDemoMain.main(PlantUMLDemoMain.java:23)
已尝试操作
- 检索到同类问题反馈称使用旧版本PlantUML可解决,已获取对应旧版本jar包,但不清楚如何正确配置替换
- 曾尝试解析jar包内引用的依赖版本并在Maven中添加对应依赖,配置后问题仍未解决
错误根因
该异常是Java 9及以上版本模块化系统访问限制导致的:当前使用的PlantUML版本直接调用了JDK内部非公开APIcom.sun.imageio.plugins.png.PNGMetadata,模块化环境下java.desktop模块默认不会向未命名模块(即业务代码及引入的第三方jar包)开放这个内部包的访问权限,因此抛出非法访问错误。
可行解决方案
- 方案1:添加JVM启动参数(无需修改依赖,成本最低)
启动程序时追加如下VM参数,直接开放对应内部包的访问权限即可解决问题:
如果在IntelliJ IDEA等IDE中运行,直接在运行配置的「VM options」输入框填入上述参数即可;如果通过Maven命令运行,可在exec-maven-plugin、maven-surefire-plugin等插件的配置项中追加该参数。--add-exports java.desktop/com.sun.imageio.plugins.png=ALL-UNNAMED - 方案2:正确替换为兼容的PlantUML旧版本
之前替换依赖失败,基本都是Maven依赖冲突导致其他组件传递引入的高版本PlantUML没有被排除,实际运行时加载的还是存在兼容问题的版本,正确操作步骤如下:- 在项目根目录执行
mvn dependency:tree,在输出的依赖树中找到所有引入PlantUML的依赖路径,对这些依赖全部添加<exclusion>规则排除传递引入的PlantUML包 - 在pom.xml中显式引入适配JDK8的PlantUML稳定版本(推荐1.2020.2版本,该版本不存在模块化兼容问题),配置示例:
<dependency> <groupId>net.sourceforge.plantuml</groupId> <artifactId>plantuml</artifactId> <version>1.2020.2</version> </dependency>- 执行
mvn clean install命令刷新依赖,再次检查依赖树确认项目中仅存在你引入的指定版本PlantUML,无其他版本残留后再运行程序即可。
- 在项目根目录执行
- 方案3:切换运行环境为JDK8
JDK8未引入模块化系统,不存在内部API访问限制,直接将项目的运行时JDK切换为JDK8版本,无需修改任何代码或依赖即可正常运行。
内容的提问来源于stack exchange,提问作者Jatel
相关产品推荐
相关产品推荐

