I have a Groovy library, available as a global shared library:
package com.example @Grab(group="org.apache.httpcomponents", module="httpclient", version="[4.5.3,)") import org.apache.http.HttpHost import org.apache.http.impl.client.HttpClients class MyClass implements Serializable { static def run() { return HttpClients.custom() .setProxy(new HttpHost("proxy.example.com", 3128)) .build() } static def debug() { return (""" this: ${this.classLoader.class.toString()} ${this.classLoader.hashCode().toString()} HttpHost: ${HttpHost.class.classLoader.class.toString()} ${HttpHost.class.classLoader.hashCode()} HttpClients: ${HttpClients.class.classLoader.class.toString()} ${HttpClients.class.classLoader.hashCode()} """) } }
And working with a Jenkins script using this library:
@Library('example') _ node { echo "${com.example.MyClass.debug()}" com.example.MyClass.run() }
When the task runs, I get the following output from debug() , followed by an error from run() :
this: class org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader 765101363 HttpHost: class hudson.ClassicPluginStrategy$AntClassLoader2 804623541 HttpClients: class hudson.ClassicPluginStrategy$AntClassLoader2 1870591909 hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.apache.http.impl.client.HttpClientBuilder.setProxy() is applicable for argument types: (org.apache.http.HttpHost) values: [http:
Itβs clear to me that some Jenkins plugins already have httpcomponents dependency, and looks like this:
- My
@Grab annotation made it load the requested version of httpclient (as mentioned in ~/.groovy/grapes ). - But this version is not downloaded or used by the Groovy library, but some other version that is dependent on some Jenkins plugin.
- And even more annoyingly,
HttpHost and HttpClients are loaded from different class loaders, so I can't even use the version of the plugin that leaked into my Groovy class loader.
Version
Plugin versions
- Groovy: 2.0
- Pipeline: 2.5
- Pipeline: Groovy: 2.30
- Pipeline: Shared Groovy Libraries: 2.8
Is there a way to run my Groovy in a class loader that is isolated from the Jenkins plugin? How do Jenkins and Groovy common library code organize class loaders? Is this a leak of classes imposed by plugins intentionally?
Is this a mistake or am I doing something wrong? I understand that I have several versions on Jenkins, so one thing to try.
As in the case, the system is unusable if Iβm not lucky that I have dependencies that another plug-in does not have, or fortunate that they are compatible with any version that the class loader detects.
classloader jenkins groovy jenkins-pipeline
Patrick
source share