Making plugin jars available at configuration time

54 views
Skip to first unread message

Greg Allen

unread,
May 6, 2015, 11:03:45 AM5/6/15
to jenkin...@googlegroups.com
I have a plugin that creates a connection to a resource. This connection
requires some plugin-specific jar files, which are bundled up in the
.hpi file and distributed with the plugin.

The plugin configuration includes connection information, such as URL
and authentication information. I have included a "test connection"
button there to allow the user to validate that their connection
information is connect. However, when the button is clicked and the
code is executed to validate the connection, I get a
java.lang.ClassNotFoundException. This class is in the jar files bundled
with the plugin, but these obviously aren't loaded at this point.

Is there some standard way for handling situations like this? Do I have
to load these jars by hand? This seems like a problem that others have
probably run into.

Thanks,

-- Greg

Jesse Glick

unread,
May 6, 2015, 12:39:40 PM5/6/15
to Jenkins Dev
On Wed, May 6, 2015 at 11:03 AM, Greg Allen <gal...@redhat.com> wrote:
> I get a java.lang.ClassNotFoundException. This class is in the
> jar files bundled with the plugin

As WEB-INF/lib/*.jar? It should “just work”. All you need do in
sources is to declare a simple Maven dependency on the library, and it
gets bundled and thus included in the plugin class loader.

Greg Allen

unread,
May 6, 2015, 12:49:42 PM5/6/15
to jenkin...@googlegroups.com
Are you saying the plugin class loader gets run at plugin configuration
time? I know it gets loaded when the plugin runs as part of a job.

This is a configuration time issue for me. Should it "just work" then
as well?

-- Greg

Jesse Glick

unread,
May 6, 2015, 1:11:32 PM5/6/15
to Jenkins Dev
On Wed, May 6, 2015 at 12:49 PM, Greg Allen <gal...@redhat.com> wrote:
> Are you saying the plugin class loader gets run at plugin configuration
> time? I know it gets loaded when the plugin runs as part of a job.

The question is meaningless. There is no “plugin configuration time”
nor plugins “run as part of a job”. If a plugin is installed and
active, it is loaded during the Jenkins session, period.

Greg Allen

unread,
May 6, 2015, 2:16:11 PM5/6/15
to jenkin...@googlegroups.com
OK, now I get it.

> As WEB-INF/lib/*.jar? It should “just work”. All you need do in
> sources is to declare a simple Maven dependency on the library, and it
> gets bundled and thus included in the plugin class loader.

And yes, I have declared Maven dependency on the library and I can see
it is bundled in with the plugin.

But I still get the ClassNotFoundException. Why would it not be getting
loaded?

-- Greg

Jesse Glick

unread,
May 6, 2015, 2:20:34 PM5/6/15
to Jenkins Dev
On Wed, May 6, 2015 at 2:16 PM, Greg Allen <gal...@redhat.com> wrote:
> I still get the ClassNotFoundException. Why would it not be getting loaded?

Well the fact that you are talking about a ClassNotFoundException,
rather than a NoClassDefFoundError (with a ClassNotFoundException as
its root cause), is a red flag. That implies that something—your
code—is loading a class reflectively rather than statically, and
presumably passing the wrong ClassLoader. Perhaps your library makes
the shoddy assumption that
Thread.currentThread().getContextClassLoader() can be used to load its
own classes (which would *not* be true for code loaded in a Jenkins
plugin).

Greg Allen

unread,
May 7, 2015, 7:32:10 AM5/7/15
to jenkin...@googlegroups.com


On 05/06/2015 02:20 PM, Jesse Glick wrote:
Well the fact that you are talking about a ClassNotFoundException,
rather than a NoClassDefFoundError (with a ClassNotFoundException as
its root cause), is a red flag. That implies that something—your
code—is loading a class reflectively rather than statically, and
presumably passing the wrong ClassLoader. Perhaps your library makes
the shoddy assumption that
Thread.currentThread().getContextClassLoader() can be used to load its
own classes (which would *not* be true for code loaded in a Jenkins
plugin).

The problem seems to be that I am using JNDI to load the class as part of the InitialContext constructor:

        Properties props = new Properties();
        props.setProperty("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory");   
        props.setProperty("connectionfactory.qpidConnectionfactory", url);
        return new InitialContext(props);

And then I end up with this:

javax.naming.NoInitialContextException: Cannot instantiate class: org.apache.qpid.jndi.PropertiesFileInitialContextFactory [Root exception is java.lang.ClassNotFoundException: org.apache.qpid.jndi.PropertiesFileInitialContextFactory]
        at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:674)
        at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
        at javax.naming.InitialContext.init(InitialContext.java:242)
        at javax.naming.InitialContext.<init>(InitialContext.java:216)
        ............................

This seems to be a pretty standard way to set up the initial context for JNDI, and it works outside of my plugin.

Is there another way to do this?

Thanks,

-- Greg

Jesse Glick

unread,
May 7, 2015, 9:54:11 AM5/7/15
to Jenkins Dev
On Thu, May 7, 2015 at 7:32 AM, Greg Allen <gal...@redhat.com> wrote:
> This seems to be a pretty standard way to set up the initial context for
> JNDI, and it works outside of my plugin.

Well, so long as you are not running in a module system/container, it will work.

http://docs.oracle.com/javase/jndi/tutorial/beyond/misc/classloader.html
describes the usual workaround.

Jason Swager

unread,
May 7, 2015, 10:43:28 AM5/7/15
to jenkin...@googlegroups.com
I'm having the same problem.  

I have a plugin that's based on the email-ext.  In one of the Validate buttons called from the global config page, I make use of a class that's implemented in a non-Jenkins JAR file.  That JAR is referenced in the <depedencies> section of the pom.xml, it appears in the maven pre-build directory, and can be extracted from the HPI after a build.  The JAR is there.  But when I try to instantiate the class, I get a NoClassDefFoundError (com/company/mylibrary/MyClass) followed by a ClassNotFoundException (com.company.mylibrary.MyClass)

I'm working with pretty much the baseline email-ext code, except the addition of the Validate button.  No special JNDI stuff that I'm aware of.

Greg Allen

unread,
May 7, 2015, 1:16:49 PM5/7/15
to jenkin...@googlegroups.com
On 05/07/2015 09:54 AM, Jesse Glick wrote:
> http://docs.oracle.com/javase/jndi/tutorial/beyond/misc/classloader.html
> describes the usual workaround.
OK, It looks like I need to add my plugins jar files onto the classpath
following the example above.

But how do I find the path to those jar files in my plugin code? Or is
there a way in the code to get a list of all the jar associated with a
plugin?

-- Greg

Jesse Glick

unread,
May 7, 2015, 3:52:27 PM5/7/15
to Jenkins Dev
On Thu, May 7, 2015 at 1:16 PM, Greg Allen <gal...@redhat.com> wrote:
> It looks like I need to add my plugins jar files onto the classpath following the example above.

Absolutely not. Just temporarily set the Thread.contextClassLoader to
SomeClassInMyPlugin.class.getClassLoader().

Jason Swager

unread,
May 7, 2015, 3:59:32 PM5/7/15
to jenkin...@googlegroups.com
I tried this - saved the current class loader, then did a setContextClassLoader(MyClass.class.getClassLoader).  It immediately failed: NoClassDefFound when trying to reference MyClass.  

Jesse Glick

unread,
May 7, 2015, 4:05:15 PM5/7/15
to Jenkins Dev
On Thu, May 7, 2015 at 3:59 PM, Jason Swager <jsw...@alohaoi.com> wrote:
> I tried this - saved the current class loader, then did a
> setContextClassLoader(MyClass.class.getClassLoader). It immediately failed:
> NoClassDefFound when trying to reference MyClass.

I was responding to Greg. Your problem may be unrelated. Fire up a
debugger and figure out what the ClassLoader receiver of the original
loadClass call is.

Greg Allen

unread,
May 7, 2015, 4:59:07 PM5/7/15
to jenkin...@googlegroups.com
Hi Jesse,

That worked for me! Thanks for both your help and your patience....

-- Greg
Reply all
Reply to author
Forward
0 new messages