asciidoctor / asciidoctorj-pdf

AsciidoctorJ PDF bundles the Asciidoctor PDF RubyGem (asciidoctor-pdf) so it can be loaded into the JVM using JRuby.
Apache License 2.0
36 stars 17 forks source link

Dependency / interaction with snakeyaml #25

Closed ahus1 closed 4 years ago

ahus1 commented 4 years ago

I've been using asciidoctorj-pdf in an environment (Intellij) where different (older?) snakeyaml version is around. This lead to an exception like this:

load error: psych -- java.lang.NoSuchMethodError: org.yaml.snakeyaml.error.Mark.(Ljava/lang/String;III[II)V

After some trial and error and adding org.yaml:snakeyaml:1.23 as a dependency, it started to work.

I wonder about two things:

Thanks, Alexander

robertpanzer commented 4 years ago

asciidoctorj-pdf doesn't actually have a dependency on snakeyaml, nor does asciidoctor-pdf. snakeyaml is a transitive dependency of JRuby, or to be exact JRuby depends on jruby-libs, which depends on rubygems:psych which in turn depends on snakeyaml 1.14! right now. I don't know the IntelliJ plugin mechanism, but doesn't it support isolation of the ClassLoaders? I know that @ysb33r also struggled specifically with snakeyaml in the gradle plugin. @ysb33r Did you find a better workaround for this?

I am a bit reluctant to redefine dependencies that should be transparent to us as this is part of the platform, similar to javax.xml to compare it to Java (before Java 11 ;-) )

ahus1 commented 4 years ago

I've been using AsciidoctorJ for quite some time, but Asciidoctorj-pdf might be the first to actually parse YAML with its templating mechanism.

AsciidoctorJ depends on jruby 9.2.7.0. From its (maven/gradle) dependency it doesn't mention snakeyaml.

After your hint about jruby-libs I digged into it and found the following snippet:

  if RUBY_ENGINE == 'jruby'
    DEFAULT_SNAKEYAML_VERSION = '1.23'.freeze
  end

Therefore 1.23 seems to be safe for now. The JAR itself is also contained inside jruby-libs. But apparently it doesn't load it voluntarily if it find a different version in the class path.

In IntelliJ there is a (classic) classloader hierarchy: any class not found in the plugin is looked up in IntelliJ core. If verified that it works that way with a different example. And there is the JRuby class loader. IntelliJ includes an older version of snakeyaml, but it seems that the JRuby class loader doesn't get the priority it should have. If I include the snakeyaml explicitly inside the plugin, the explicitly included version takes precedence.

Hmm... seems that I need to find out how to boost the priority of the JRuby class loader...

ahus1 commented 4 years ago

Issue https://github.com/jruby/jruby/issues/5573 describes something similar, but doesn't provide a solution. Previous discussion in #16.

ahus1 commented 4 years ago

For now I'll keep the extra dependency of snakeyaml as it solves the issue for me and no other solution is in sight.

ysb33r commented 4 years ago

Yes, it's a pain. Our issue was caused by Gradle leaking snakeyml on to the classpath.