Daniel Hári
Daniel Hári

Reputation: 7784

URLClassLoader can't handle jar:file urls?

I want to load a library in separated classloader because don't want to add directly as dependency to do not conflict with other versions in the project. I created a loader:

public LibLoader(String resourcePath) {
    //resourcePath="/lib/Log4JHack-1.0.jar"
    URL url = getClass().getResource(resourcePath);
    loader = new URLClassLoader(new URL[] {url}, getClass().getClassLoader());
}

url = [file:/D:/..../lib/Log4JHack-1.0.jar]

if url is a file, then it works well.

url = [jar:file:/C:/..../Log4JHackLoader-1.0.jar!/lib/Log4JHack-1.0.jar]

if url is a jar:file (jar inside jar), then it don't work:

ERROR StatusLogger Unable to open jar:jar:file:/C:/Users/Dani/.m2/repository/hu/daniel/hari/log4jhack/Log4JHackLoader/1.0/Log4JHackLoader-1.0.jar!/lib/Log4JHack-1.0.jar!/META-INF/log4j-provider.properties java.net.MalformedURLException: no !/ in spec
    at java.net.URL.<init>(URL.java:620)
    at java.net.URL.<init>(URL.java:483)
    at java.net.URL.<init>(URL.java:432)
    at java.net.JarURLConnection.parseSpecs(JarURLConnection.java:175)
    at java.net.JarURLConnection.<init>(JarURLConnection.java:158)
    at sun.net.www.protocol.jar.JarURLConnection.<init>(JarURLConnection.java:81)
    at sun.net.www.protocol.jar.Handler.openConnection(Handler.java:41)
    at java.net.URL.openConnection(URL.java:972)
    at java.net.URL.openStream(URL.java:1038)
    at org.apache.logging.log4j.util.ProviderUtil.loadProvider(ProviderUtil.java:79)
    at org.apache.logging.log4j.util.ProviderUtil.<init>(ProviderUtil.java:66)
    at org.apache.logging.log4j.util.ProviderUtil.lazyInit(ProviderUtil.java:122)
    at org.apache.logging.log4j.util.ProviderUtil.hasProviders(ProviderUtil.java:106)
    at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:91)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.log4j.capture.log4j2.StringLoggerCapture.<clinit>(StringLoggerCapture.java:34)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.Log4j2Hack.doRender(Log4j2Hack.java:30)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.Log4j2Hack.render(Log4j2Hack.java:23)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.renderer.AbstractLog4jRendererAdapter.render(AbstractLog4jRendererAdapter.java:25)
    at hu.daniel.hari.log4jpattern.logrenderer.service.LogRendererServiceImpl.getOutput(LogRendererServiceImpl.java:44)
    at hu.daniel.hari.log4jpattern.logrenderer.service.LogRendererServiceImpl.render(LogRendererServiceImpl.java:37)
    at hu.daniel.hari.log4jpattern.logrenderer.TestMain.main(TestMain.java:14)
Caused by: java.lang.NullPointerException: no !/ in spec
    at sun.net.www.protocol.jar.Handler.parseAbsoluteSpec(Handler.java:171)
    at sun.net.www.protocol.jar.Handler.parseURL(Handler.java:151)
    at java.net.URL.<init>(URL.java:615)
    ... 20 more

Since I want to pack the loadable Log4JHack-1.0.jar to Log4JHackLoader-1.0.jar, I need a solution for loading from inside jar.

Upvotes: 0

Views: 1722

Answers (2)

Herv&#233; Girod
Herv&#233; Girod

Reputation: 547

The github.com/squark-io/nested-jar-classloader project is able to load classes in nested jar files, but has a lot of external dependencies. I added this same mechanism in my project (sourceforge.net/projects/mdiutilities/) but in this case without external dependencies.

These two projects do not work by making a temporary copy of the nested jar files, but directly load the classes bytes.

Upvotes: 0

ck1
ck1

Reputation: 5443

It's not 100% clear to me what you're trying to do here. Why are you trying to include conflicting dependencies in your classpath?

In any case, this is a known limitation of UrlClassLoader. Have you considered extracting the nested jar as a temporary file on the file system, and then pointing your class loader to it?

Upvotes: 1

Related Questions