sphinx-gradle-plugin icon indicating copy to clipboard operation
sphinx-gradle-plugin copied to clipboard

Cannot generate plantuml diagrams

Open MaciejWadowski opened this issue 5 years ago • 8 comments

With gradle 6.5 and above running task does not generate uml diagrams. Error below:

WARNING: error while running plantuml

Exception in thread "main" java.lang.NoClassDefFoundError: org/gradle/internal/classpath/Instrumented
  at net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils.getenv(GraphvizUtils.java:151)
  at net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils.getenvDefaultConfigFilename(GraphvizUtils.java:143)
  at net.sourceforge.plantuml.Option.<init>(Option.java:111)
  at net.sourceforge.plantuml.Run.main(Run.java:89)
Caused by: java.lang.ClassNotFoundException: org.gradle.internal.classpath.Instrumented
  at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
  ... 4 more

MaciejWadowski avatar Sep 30 '20 11:09 MaciejWadowski

Have you tried pip installing graphviz on the system first? I don't believe it comes with plantuml directly - it probably needs to be on the path or pointed at via your sphinx config file.

firthl avatar Sep 30 '20 15:09 firthl

Ok my mistake, the documentation stop generating after 6.6 gradle version, 6.5.x still works well. I don't think that my configuration is bad if it's working on gradle 6.5.1.

MaciejWadowski avatar Oct 01 '20 09:10 MaciejWadowski

Thanks for reporting. Just don't have enough time to look into this at the moment since I've just joined a company. Any pull requests would be appreciated.

trustin avatar Oct 01 '20 15:10 trustin

I've been bitten by this too. My work-around is to generate documentation manually outside Gradle. I set plantuml in my own conf.py to use a JAR on my local machine. But it would be nice if it could be portable.

I have investigated, and I think I can pin-point the problem. I don't understand the mechanism at all really, or why upgrading Gradle brought it on. Fortunately, that's not the bit that needs fixing.

The error can be reproduced with particular versions of plantUML, alone, at the command prompt:

PS clean> java -jar plantuml-1.2020.4.jar testdot.uml
Exception in thread "main" java.lang.NoClassDefFoundError: org/gradle/internal/classpath/Instrumented
        at net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils.getenv(GraphvizUtils.java:151)
        ... 

Whereas:

PS clean> java -jar plantuml.1.2020.21.jar testdot.uml

gives me the image I'm entitled to.

Now, the Gradle plug-in depends on classes from the Sphinx-Maven plug-in, and that cites 1.2020.4 specifically https://github.com/trustin/sphinx-maven-plugin/blob/c28805c3e5d1c11d79d3e0d913eb6b11d284e1be/pom.xml#L93. This is one that exhibits the problem. I think updating this is the clean solution.

contrib-plantuml is simply picking up the plantuml command from configuration. The code that composes the command is at: https://github.com/trustin/sphinx-maven-plugin/blob/c28805c3e5d1c11d79d3e0d913eb6b11d284e1be/src/main/java/kr/motd/maven/sphinx/SphinxRunner.java#L86-L94. So the Maven plug-in finds the JAR via the class path, and having a newer Jar on the path ahead of the culprit may do the trick.

I am wondering if there is anything I can do in my Gradle script to force the version up to 1.2020.21?


PS. @trustin : this is awesome stuff, that I realise rests on the shifting sands of others' work. Thanks for doing it. I find it enormously helpful to be able to express my ideas in UML in Sphinx. After working this way most of the year, including to describe some structures inside CPython, I wonder how the Python core devs manage to communicate without using it.

jeff5 avatar Dec 06 '20 12:12 jeff5

Thanks everyone for your patience and kind words! I've just released a new version that depends on PlantUML 1.2021.1. Please let me know if the new version fixes your problem. :bow:

trustin avatar Feb 11 '21 11:02 trustin

Unfortunately, it still seems to have a problem. Let me take another look later.

trustin avatar Feb 11 '21 11:02 trustin

Here's my analysis:

Since 6.5, Gradle instruments the code that intercepts various potentially important calls into the JARs in the dependency of a plugin. For example, System.getProperty() is redirected to a method in Instrumented. This is not a problem as long as the instrumented JAR is executed in the JVM run by Gradle, because the class Instrumented is available in the class path. However, in our case, we launch a new JVM with the instrumented PlantUML JAR. Because this new JVM doesn't have Gradle classes in the class, we get a NoClassDefFoundException.

There are a few options to fix this problem:

  • Gradle team fixes https://github.com/gradle/gradle/issues/14727
  • We modify sphinx-maven-plugin so we provide a dummy Instrumented class in the class path when running PlantUML. However, this can break if Gradle team decides to break the API compatibility of Instrumented.
  • We modify sphinx-maven-plugin so it allows sphinx-gradle-plugin to specify the necessary Gradle JARs in the class path.
  • We change the way how PlantUML JAR is loaded in sphinx-gradle-plugin so Gradle doesn't instrument anything into PlantUML. (Is this ever possible?)

trustin avatar Feb 11 '21 12:02 trustin

Workaround:

  1. Download plantuml.jar to your project.
  2. define env 'plantuml' in task, like that: env 'plantuml', "java -jar ${projectDir}/src/main/resources/plantuml.jar"

Basically you have to define plantuml inside gradle task, not plugin, otherwise Exception will be thrown

MaciejWadowski avatar Jun 29 '21 13:06 MaciejWadowski