It is not possible to use external third party libaries with optional dependencies properly in shared libraries for Jenkins.
I have a shared library which uses Commons Configurations 2 to read varios configuration files, mostly written as YAML documents.
Commons configurations uses SnakeYAML to read YAML documents and the dependency to SnakeYAML is defined as optional as follows:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
<optional>true</optional>
</dependency>
According to the documentation of Maven how optional dependencies work an optional dependency is not added by default to the classpath. If a person wants to the part of the library which depends on the optional dependency, it must add this dependency to his own POM.
As I was going to use Commons Configuration 2 in conjunction with SnakeYAML, I defined the following variable in vars/readConfig.groovy
as follows:
@Grapes([
@Grab(group = "org.apache.commons", module = "commons-configuration2", version = "2.7"),
@Grab(group = "org.yaml", module = "snakeyaml", version = "1.26")
])
import org.apache.commons.configuration2.BaseConfiguration
import org.apache.commons.configuration2.Configuration
import org.apache.commons.configuration2.YAMLConfiguration
def call() {
Configuration config = new BaseConfiguration();
YAMLConfiguration yamlConfiguration = new YAMLConfiguration();
}
Calling readConfig()
from a shared Library results in a java.lang.ClassNotFoundException
with the following message
java.lang.ClassNotFoundException: org.yaml.snakeyaml.DumperOptions
at jenkins.util.AntClassLoader.findClassInComponents(AntClassLoader.java:1387)
at jenkins.util.AntClassLoader.findClass(AntClassLoader.java:1342)
at jenkins.util.AntClassLoader.loadClass(AntClassLoader.java:1089)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetPublicMethods(Class.java:2902)
at java.lang.Class.getMethods(Class.java:1615)
at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1336)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1197)
at java.beans.Introspector.getBeanInfo(Introspector.java:426)
at java.beans.Introspector.getBeanInfo(Introspector.java:173)
at groovy.lang.MetaClassImpl$15.run(MetaClassImpl.java:3313)
at java.security.AccessController.doPrivileged(Native Method)
at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:3311)
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3288)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:260)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:302)
...
I also checked the directory ~/.groovy/grapes
for the presence of all needed jars and they are there.
jenkins@cb765137c926:~/.groovy$ find . -name "*.jar"
./grapes/commons-logging/commons-logging/jars/commons-logging-1.2.jar
./grapes/org.apache.commons/commons-configuration2/jars/commons-configuration2-2.7.jar
./grapes/org.apache.commons/commons-lang3/jars/commons-lang3-3.9.jar
./grapes/org.apache.commons/commons-text/jars/commons-text-1.8.jar
./grapes/org.yaml/snakeyaml/jars/snakeyaml-1.26.jar
To do a cross-check I wrote the following Groovy script and was able to execute it on my computer successfully.
@Grapes([
@Grab(group = 'org.apache.commons', module = 'commons-configuration2', version = '2.7'),
@Grab(group = 'org.yaml', module = 'snakeyaml', version = '1.26'),
@GrabConfig(systemClassLoader = true)
])
import org.apache.commons.configuration2.*
println("Start")
YAMLConfiguration y = new YAMLConfiguration()
println y
So, I am not able to guess the reason for this problem, as I am not so familiar with the internals of Jenkins. But it would be great to know if there is a way to get it working as intended.
Grab is built upon Ivy. What we do in our Ivy config to get optional dependencies is to add optional
to the element conf
of the annotation.
@Grab(group='org.apache.commons', module='commons-configuration2',
version='2.7', conf='default,optional')