getResourceAsStream returns null in plugin in daemon mode

I am writing a gradle plugin in which I tried to copy a resource from the same plugin jar file to file system. I am using:

Thread.currentThread().contextClassLoader.getResourceAsStream(resourcePath)

to get the stream, but the stream is null most of time if I enabled daemon mode:

org.gradle.daemon=true

It returns a valid stream at some random rare time.

If it’s not set to true, it always returns a valid stream.

Is this a bug of gradle in daemon time?

Thanks.

BTW, I tried this on the following versions, both have the same issue:

------------------------------------------------------------ Gradle 1.12 ------------------------------------------------------------

Build time:

2014-04-29 09:24:31 UTC Build number: none Revision:

a831fa866d46cbee94e61a09af15f9dd95987421

Groovy:

1.8.6 Ant:

Apache Ant™ version 1.9.3 compiled on December 23 2013 Ivy:

2.2.0 JVM:

1.7.0_45 (Oracle Corporation 24.45-b08) OS:

Linux 3.13.0-24-generic amd64

------------------------------------------------------------ Gradle 2.0 ------------------------------------------------------------

Build time:

2014-07-01 07:45:34 UTC Build number: none Revision:

b6ead6fa452dfdadec484059191eb641d817226c

Groovy:

2.3.3 Ant:

Apache Ant™ version 1.9.3 compiled on December 23 2013 JVM:

1.7.0_45 (Oracle Corporation 24.45-b08) OS:

Linux 3.13.0-24-generic amd64

Why are you using the context class loader?

If the resource is part of your plugin jar, you should use «Plugin Class».getClassLoader().getResourceAsStream(…).

class.getClassLoader() has the same issue.

To make it easier, I created an example plugin. Please download it at: https://drive.google.com/file/d/0BwkABVhKVNZeTXgxbU11dnM4ck0/edit?usp=sharing.

Extract the tar.gz file, go to the top folder, run:

$ gradle upload

It will upload the plugin jar to folder “repo”.

Now go to the “example” folder, run:

$ gradle dummy

The meaningful output is 1.a/1.b/4.a/4.b. For non-daemon running, you will always see 1.b/4.b output false, that’s correct. But if you run it with:

$ gradle dummy --daemon

run it multiple times, you’ll see 1.b/4.b sometimes true, sometimes false.

In case you didn’t see the issue, go to run “gradle upload” again, and repeat the example.

Here is one snapshot of the output:

$ gradle dummy --daemon :dummy 1.a: jar:file:/home/dummy/repo/org/example/gradle/gradle-dummy-plugin/0.1.0/gradle-dummy-plugin-0.1.0.jar!/a.txt 1.b: false 2.a: null 2.b: true 3.a: null 3.b: true 4.a: jar:file:/home/dummy/repo/org/example/gradle/gradle-dummy-plugin/0.1.0/gradle-dummy-plugin-0.1.0.jar!/a.txt 4.b: true 5.a: null 5.b: true 6.a: null 6.b: true

BUILD SUCCESSFUL

Total time: 0.624 secs

Thanks!

getResource("/a.txt") or put your resource into same package as your class.

Hi, Radim

I tried it, but the issue is still there. The odd thing is that “gradle upload” sometime generates a “good” jar which doesn’t have this issue, and other time it generates a “bad” jar which does. And when it has the issue, it sometimes can find the resource, but most of the time it can’t. Please try it on the dummy plugin.

Thanks!

I’m seeing this as well. Command line execution of my unit test works, but execution using the plugin or execution of my unit test from intellij fails. For a while intellij worked but I’m not sure how. There’s some intermittent quality here. Perhaps I’m getting lost in threads.

In my case, I’ve added a trustStore as a resource to my jar (in several locations while testing) and my confluence class will extract it to a local file. I’ve tried multiple options but I can’t always get the certs resource. when it fails, I get null even though in the jar I have my.cacerts at root, next to the class and at same level as MyBuildPlugin class.

Any idea what I’m missing?

InputStream is = MyBuildPlugin.getClassLoader().getSystemResourceAsStream("my.cacerts")
        OutputStream os = new FileOutputStream(storeFile)
        Files.copy(is, os)

Hard to be definitive given the intermittent nature, but looks to be the JDK’s URL cache. It’s also hard to be definitive given that the actual impl of URLConnection that is used for loading resources out from the classpath is native.

I was unable to get it to fail after adding this to the task impl before all the printlns:

new URLConnection(new URL("file:///")) {
  {
    setDefaultUseCaches(false)
  }
    @Override
  void connect() throws IOException {
    }
}

I’m going to propose setting this globally in Gradle, but if this is indeed the issue that code should unblock you.

Cool! This is the first solution to this issue, even if it’s a workaround. The issue never happens for me with this piece of code.

Thank you, Luke!

Still seems intermittent to me. I think it has something to do with intellij building vs command line building. I gave up and used a different design to get my resource and am happy to test things if you have theories.

Peter