6

I have got two working directories containing java code and resources, one is for testing and the other one is production.

src/main/java
src/main/resources

src/test/java
src/test/resources

When running my code and reading a file from FileInputStream like this:

new FileInputStream("./someFile.json");

As long a the file is located in the root of the project this works fine. It also works if I have the file in the resource folder and point directly to it like this:

new FileInputStream("src/test/resources/someFile.json");

Is there a way declaring src/test/resources in gradle as the main folder where FileInputStream looks for resources?

If i put my file like this it works fine.

enter image description here

But when I put the file in src/test/java/resources like this

enter image description here

I get a fileNotFoundException.

I need a way to add this directory to be scanned with gradle.



Adding this to build.gradle still throws a fileNotFoundException.

sourceSets {
test {
    java {
        srcDirs = ['src/test/java']
    }
    resources {
        srcDirs = ['src/test/resources']
        }
    }
}
firozaqiwu
  • 195
  • 2
  • 10
  • Do not access resources as if they were files. If you need to open an `InputStream` to a resource then use [`Class#getResourceAsStream(String)`](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Class.html#getResourceAsStream(java.lang.String)). Note the Gradle source directories are "roots" of the classpath/modulepath (and as such are not included in the resource name). – Slaw Oct 18 '20 at 08:35
  • Yes you did misunderstand it. I am only trying to access test resource folder from test code and not production code. – firozaqiwu Oct 18 '20 at 08:46
  • Then that's good :) My first comment still applies, however. – Slaw Oct 18 '20 at 09:12
  • 1
    Updated my question for more clarity. I only wish to be able to access the correct resource directory through gradle. Probably something to do with sourceSets. – firozaqiwu Oct 18 '20 at 10:55
  • The build tool you're using is irrelevant (and Gradle already handles resources under `src/test/resources` properly out-of-the-box as part of the `java` plugin). Resources are accessed via `Class#getResourceAsStream(String)` and related API. Do not try to use `FileInputStream` to read resources. – Slaw Oct 18 '20 at 19:15
  • @Slaw I disagree for test resources. Test resources (and classes) won't be packed in JAR files. Tests are usually run directly using the class files and the test resources will not necessarily be available next to the test classes, so `getResourceAsStream` won't work. Gradle and Maven run tests from the project directory, so its perfectly fine (and sometimes necessary) to access test resource files directly. – Lukas Körfer Oct 19 '20 at 01:15
  • @LukasKörfer If it's actually a test **resource** then it should _always_ be available to `getResourceAsStream` assuming you set everything up correctly (as both Gradle and Maven do). The whole point of resources is that they're placed on the classpath/modulepath allowing them to be accessed independently of the application's location. If the file is not a resource, but instead an external file that's nonetheless part of the project, then that's a different scenario. – Slaw Oct 19 '20 at 01:18
  • You are right with your point that resource files are automatically available via `getResourceAsStream` using Gradle / Maven. I was confused for a moment, because Gradle separates class files and resource files in its `build` folder, but nevertheless both are added to the classpath for tests. Nevertheless tests may need to access files directly (e.g. as `File` instances) and they are perfectly fine to do so. Tests won't be shipped anywhere. Of course you could distinguish between test resource files and files that are just used by tests, but thats not necessary imho. – Lukas Körfer Oct 19 '20 at 01:42
  • @LukasKörfer I agree _in practice_ it's unlikely that tests need to worry about files vs. resources. However, I'm of the opinion that if you can do something theoretically correct the first time then you should. Especially since it's the same amount of work to use e.g. `File` as it is to use `getResourceAsStream` (I actually think the latter is easier to use in this case). Also, Gradle now packages the production code in a JAR file when executing the `run` task if `java.modularity.inferModulePath = true`, so it's _possible_ tests could undergo the same treatment in the future. – Slaw Oct 19 '20 at 05:59

1 Answers1

4

If you use the java or, since you seem to be building a command line application, the application plugin, everything will be set up for you out of the box:

plugins {
    id 'application'
}

You can remove all your sourceSet configurations and just load the file like so:

new FileInputStream("/someFile.json");

(Notice that I wrote / instead of ./ which changes the meaning from "look in the current directory, the project root" to "look in the root of a classpath resource".)
It would be even better to follow Slaw's comment under the question and locate the file via Class#getResourceAsStream(String) - but that's going beyond your question a bit.

barfuin
  • 16,865
  • 10
  • 85
  • 132
  • "_but that's going beyond your question a bit_" – I disagree. Resources should **never** be read using `FileInputStream`. Resources are not necessarily files which means it's wrong to assume they are (e.g. once packaged in a JAR file they are entries in a JAR file, not files themselves). The proper way to open an `InputStream` to a resource is via `Class#getResourceAsStream(String)` (or related API). The build tool being used is irrelevant beyond placing the resources in the correct source directory (in this case `src/test/resources`). – Slaw Oct 18 '20 at 19:12
  • 1
    You‘re right @Slaw! That‘s why I mentioned it again. – barfuin Oct 19 '20 at 04:53
  • when using the `Class#getResourceAsStream(String)`, I get a no JSON input found error. – firozaqiwu Oct 21 '20 at 08:54
  • Maybe this helps? https://stackoverflow.com/q/1464291/1005481 It has a Jon Skeet answer! – barfuin Oct 21 '20 at 11:01
  • I tried your suggestion i.e the application plugin, but i keep getting "Gradle Error Marker" in the Problems view of the IDE, and a red-cross overlay on the `build.gradle` file. Any idea? I am using Gradle v7.1.1 if that matters. – jumping_monkey Aug 20 '21 at 04:55