SvnKit and Gradle classloader filtering


(detelinyordanov) #1

Hi,

We have a build that needs to do some subversion checks before executing certain tasks. For this purpose we wrote a simple svn utility that uses SvnKit to retrieve the SVN status information, this class was put under /buildSrc directory of the project.

Unfortunately it turned out that using the SVNKit with cached and encrypted SVN credentials does not work - it seems that SvnKit loads its drivers for reading encrypted credentials only if certain classes are available on the classpath, e.g.:

ClassLoader loader = SVNJNAUtil.class.getClassLoader();

if (loader == null) {

loader = ClassLoader.getSystemClassLoader();

}

if (loader != null && loader.loadClass(JNA_CLASS_NAME) != null) {

ourIsJNAPresent = true;

}

See http://svn.svnkit.com/repos/svnkit/tags/1.7.4-rc5/svnkit/src/main/java/org/tmatesoft/svn/core/internal/util/jna/SVNJNAUtil.java

Since our utility class was on the buildscript’s classpath and was not able to load this class, it seemed that Gradle is somehow restricting access to it. After some debugging we figured that Gradle uses a ‘org.gradle.util.FilteringClassLoader’ to allow access only to certain packages to the build script. In Gradle 1.0-m6 we used the following workaround to overcome the issue:

//workaround for SvnKit failing to load ‘com.sun.jna.Library’ and not adding os-specific password storages

for (ClassLoader cl = buildscript.getClassLoader(); cl.getParent() != null; cl = cl.getParent()) {

if (cl instanceof FilteringClassLoader) {

((FilteringClassLoader)cl).allowPackage(‘com.sun.jna’)

}

}

However, with Gradle 1.0-m9 this does not work anymore and after further investigation we came up to:

//workaround for SvnKit failing to load ‘com.sun.jna.Library’ and not adding os-specific password storages

import org.tmatesoft.svn.core.wc.SVNWCUtil

for (ClassLoader cl = SVNWCUtil.class.getClassLoader(); cl.getParent() != null; cl = cl.getParent()) {

if (cl instanceof FilteringClassLoader) {

((FilteringClassLoader)cl).allowPackage(‘com.sun.jna’)

}

}

My question is whether there will be (or is) some official support for configuring this, so that we do not need to do these kind of tricks. I guess that there are other APIs that are doing similar checks thus it seems a good idea to add some information to the Gradle User Guide about classloader filtering that Gradle does.

Regards,

Detelin


(detelinyordanov) #2

By the way,

I figured out the reason for changed behavior in latest Gradle 1.0-m9 and rc-1, it’s because of changed constructor of ‘MultiParentClassLoader’:

https://github.com/gradle/gradle/commit/d8b88471a9e6101684236e74aead6785c8ed1bb8#diff-1

Since parent class loader is no more visible, it is not possible to reach the ‘FilteringClassLoader’ by just following the class loader hierarchy.

I still think classloading deserves some documentation since otherwise people will be struggling to figure out how it works.

Regards,

Detelin