Maven: Not able to read the file from resource folder - java

Package
|
|------src/main/java
|------resources
|---- config.properties
In pom.xml, I have set resoucres directory as follows
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
I'm able to get the absolute path of the file. But When I try to read or check whether it is a file or directory, it is return false.
sample.java
File configFile = new File("config.properties");
System.out.println("PATH="+newFile.getAbsolutePath());
System.out.println("IsFile="+newFile.isFile());
System.out.println("CanRead="+configFile.canRead());
Output
PATH=D:\JCB\MyWorkSpace_LunaJEE\MessageProcessor\config.properties
IsFile=false
CanRead=false
Any help will be appreciated.

In pom.xml, I have set resoucres directory as follows
That defines the directory where resources will be stored as part of the Maven build structure - so it specifies where Maven should look for resource files to include in your program. It does not define where files can be found when running your application. It is not really a good idea to change from the Maven conventions, keep it as src/main/resources if you can. If you use external tooling on top of Maven, you may get conflicts otherwise.
What is the important part is what happens with the files when the application is built by Maven when you do for example a mvn clean install.
whatever is in src/main/java is compiled and the classes are put in the target directory, in their proper package structure. The files and directories in the src/main/resources folder are copied to that same target directory. The resources are thus made part of your Java program and are available on the classpath; if you would let Maven build your application into an executable jar at this point for example, the resources will be packaged together with the classes inside that jar.
To properly load the resource files packaged with your application, you should use Java's classloader system. This question's answer demonstrates that in detail. To change your current test code, you would rather do something like this:
InputStream is = getClass().getClassLoader().getResourceAsStream("config.properties");
if(is != null){
// yep, the file exists on the classpath! Now load it with the InputStream
}

The file is not in D:\JCB\MyWorkSpace_LunaJEE\MessageProcessor\config.properties, but in the resources folder there, so it does not exist and thus is neither file nor directory. I would suggest putting it in /src/main/resources and then accessing it via getResourceAsStream( name );

Related

Getting resource file from inside jar

I need to get a resource from inside the root of the application when its packed into jar. My project is like this:
ProjectRoot
resource.txt //want to access from here
src
main
java
package1
package2
package3
Main.java
target
app.jar
classes
resource.txt //works when here
package1
package2
package3
Main.class
I use this code:
Path path = Paths.get("resource.txt");
When run before packaging into a jar, it finds the file just fine (inside ProjectRoot). When running the jar, it can't find it, and transforms this path to target/resource.txt.
This code:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"resource.txt")));
when run before packaging looks for the resource inside target/classes. After packaging it claims to taking the resource from .../target/app.jar!/resource.txt.
This code:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"/resource.txt")));
I can't understand where's looking for the resource, but it doesn't seem to be ProjectRoot.
All I want to do is to place the resource inside ProjectRoot and be able to access it from both outside jar (when running the class files from IDE) and inside (after having packaged the files into a jar file using Maven).
EDIT: I NEED THE CODE TO WORK BOTH FOR PRE- AND POST- packaging. MEANING: If I run a Main.java FROM INSIDE IDE IT WOULD GET THE RESOURCE; IF I PACKAGE EVERYTHING INTO JAR AND RUN JAR IT WOULD GET THE RESOURCE - ALL WITH THE SAME CODE.
Use: Main.class.getResource("/resource.txt").
Note that your attempt using any call to getClassLoader is strictly worse (it's more text, and will fail more often, because that class loader can in exotic cases be null (specifically, when you're part of the bootstrap loader), whereas calling getResource directly on the class always works.
The reason your snippet does not work is because when invoking getResource on the classloader, you must NOT start the resource with a slash. When invoking on a class directly, you can (if you don't, it'll be relative to the package of the class you're calling it on, if you do, it'll be relative to the root).
TL;DR: Of the forms SomeClass.class.getClassLoader().getResource, getClass().getResource and MyClass.class.getResource, only the last one is correct, the rest are strictly inferior and therefore should not be used at all.
Maven uses something called the Standard Directory Layout. If you don't follow this layout then the plugins can't do their job correctly. Technically, you can configure Maven to use different directories but 99.999% of the time this is not necessary.
One of the features of this layout is that production files go in:
<project-dir>/src/main/java
All *.java files
<project-dir>/src/main/resources
All non-*.java files (that are meant to be resources)
When you build your project the Java source files are compiled and the *.class files are put into the target/classes directory; this is done by the maven-compiler-plugin. Meanwhile, the resource files are copied from src/main/resources into target/classes as well; the maven-resources-plugin is responsible for this.
Note: See Introduction to the Build Lifecycle for more information about phases and which plugins are executed by which phase. This Stack Overflow question may also be useful.
When you launch your application from the IDE (possibly via the exec-maven-plugin) the target/classes directory is put on the classpath. This means all the compiled classes from src/main/java and all the copied resources from src/main/resources are available to use via the classpath.
Then, when you package your application in a JAR file, all the files in target/classes are added to the resulting JAR file (handled by the maven-jar-plugin). This includes the resources copied from src/main/resources. When you launch the application using this JAR file the resources are still available to use via the classpath, because they're embedded in the JAR file.
To make resource.txt available on the classpath, just move:
<project-dir>/resource.txt
To:
<project-dir>/src/main/resources/resource.txt.
Then you can use Class#getResource with /resource.txt as the path and everything should work out for you. The URL returned by getResource will be different depending on if you're executing against target/classes or against the JAR file.
When executing against target/classes you'll get something like:
file:///.../<project-dir>/target/classes/resource.txt
When executing against the JAR file you'll get something like:
jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt
Note: This all assumes resource.txt is actually supposed to be a resource and not an external file. Resources are typically read-only once deployed in a JAR file; if you need a writable file then it's up to you to use a designated location for the file (e.g. a folder in the user's home directory). One typically accesses external files via either java.io.File or java.nio.file.*. Remember, resources are not the same thing as normal files.
Now, if you were to put resource.txt directly under <project-dir> that would mean nothing to Maven. It would not be copied to target/classes or end up in the JAR file which means the resource is never available on the classpath. So just to reiterate, all resources go under src/main/resources.
Check out the Javadoc of java.lang.Class#getResource(String) for more information about the path, such as when to use a leading / and when not to. The link points to the Javadoc for Java 12 which includes information about resources and modules (JPMS/Jigsaw modules, not Maven modules); if you aren't using modules you can ignore that part of the documentation.

Using relative path in a maven project

I have a maven project with these standard directory structures:
src/main/java
src/main/java/pdf/Pdf.java
src/test/resources
src/test/resources/files/x.pdf
In my Pdf.java,
File file = new File("../../../test/resources/files/x.pdf");
Why does it report "No such file or dirctory"? The relative path should work. Right?
Relative paths work relative to the current working directory. Maven does not set it, so it is inherited from whatever value it had in the Java process your code is executing in.
The only reliable way is to figure it out in your own code. Depending on how you do things, there are several ways to do so. See How to get the real path of Java application at runtime? for suggestions. You are most likely looking at this.getClass().getProtectionDomain().getCodeSource().getLocation() and then you know where the class file is and can navigate relative to that.
Why does it report "No such file or dirctory"? The relative path should work. Right?
wrong.
Your classes are compiled to $PROJECT_ROOT/target/classes
and your resources are copied to the same folder keeping their relative paths below src/main/resources.
The file will be located relative to the classpath of which the root is $PROJECT_ROOT/target/classes. Therefore you have to write in your Pdf.java:
File file = new File("/files/x.pdf");
Your relative path will be evaluated from the projects current working directory which is $PROJECT_ROOT (AFAIR).
But it does not matter because you want that to work in your final application and not only in your build environment. Therefore you should access the file with getClass().getResource("/path/to/file/within/classpath") which searches the file in the class path of which the root is $PROJECT_ROOT/target/classes.
No the way you are referencing the files is according to your file system. Java knows about the classpath not the file system if you want to reference something like that you have to use the fully qualified name of the file.
Also I do not know if File constructor works with the classpath since it's an abstraction to manage the file system it will depend where the application is run from. Say it is run from the target directory at the same level as source in that case you have to go one directory up and then on src then test the resources the files and finally in x.pdf.
Since you are using a resources folder I think you want the file to be on the classpath and then you can load a resource with:
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("<path in classpath>");
Then you can create a FileInputStream or something to wrap around the file. Otherwise use the fully qualiefied name and put it somewere like /home/{user}/files/x.pdf.

How to make a maven project recognize a file from its own directory instead of working directory?

I currently have two projects:
api-test
...
/config/config.json
...
and
ui-test
...
/config/config.json
...
In eclipse, I am adding api-test in the build path of ui-test, so that api-test is the dependency of ui-test.
However the build failed, because api-test is looking for the config.json located in api-test/config/config.json by calling:
System.getProperty("user.dir") + "/config/config.json"
which does not exist in ui-test project.
the two config.json include different contents - what would be the best solution to let each project refer to their own config.json while ui-test is referring to api-test project?
Put the files into the projects' src/main/resources directories as suggested by Maven's Standard Directory Layout. You can use relative paths to access these resources then.
See How to get file resource from Maven src/test/resources/ folder in JUnit test? For instance:
Test file existence
#Test
public void testStreamToString() {
assertNotNull("Test file missing", getClass().getResource("/sample.txt"));
...
}

Adding resources in IntelliJ for Maven project

I have a project structure like this:
src
|-main
|-java
|-com.abc.xyz
|-Login.java
I have to add a resource file to this and read the resource with
InputStream is = getClass().getResourceAsStream("launchers.properties");
This is giving null.
In Intellij I am not able to add a new package under src/main for resources folder so
that the project structure looks like this. How can I load the launchers.properties resource file into the project?
src
|-main
|-java
|-com.abc.xyz
|-Login.java
|-resources
|-com.abc.xyz
|-Login
|-launcher.properties
I tried the solution suggested by #maba but still not working
The launcher.properties should not be under a folder called Login. It should be placed directly in the src/main/resources/com/abc/xyz folder.
It is really as simple as I said but if the resources folder is not marked as a sources folder then this may be the problem.
This is the initial class and setup:
Now create the resources folder:
This newly created folder should be automatically marked as a sources folder and if it is blue color marked then it is. Otherwise you'll have to mark it manually:
Now you'll be able to add packages to it:
And now you can add the file to it:
And rerunning the application will not give you any null value back:
And the package view will surely show the launchers.properties file as well:
As #maba pointed out, your properties file should be in the same package as your class for your code to work.
So, you should have two files:
src/main/java/com/abc/xyz/Login.java
src/main/resources/com/abc/xyz/launcher.properties
If IntelliJ is showing the resource or not is beside the question. What you need to do is check if the results are included in your target artefact.
Do a build all in IntelliJ, open up the resulting WAR/JAR/EAR with your favorite ZIP viewer and browse into the "com/abc/xyz" folder. You should see both files there.
If they are, you are doing something wrong in your code. Check for typos, especially dots and spaces at the end or beginning (e.g. "launcher.properties[space]"), copy/paste the file name to make sure
If they are not there, your IntelliJ setup is wrong. Resources do not get included in your target build. Check online for tutorials how to do this with IntelliJ idea.
Follow these two steps
1) Create a directory
Right Click ==> New ==> Directory
2) Mark Directory as Resources Root
Right Click on the Direcory ==> Mark Directory as ==> Resources Root
No..... the structure is wrong.... you should not create the same package under resources, that is ugly and not proper: resources is for resources, and should not contain source packages.
When using ClassLoader.getResources(asStream)(path) method, the method just starts searching from the root of the classpath and the path name cannot start with / as leading characters. What you have to do, is to mark the resources as resources folder in IntelliJ. Then the files under resources will be listed under classpath and you can easily use them like you have done.
(I see in previous answers this option is not available yet in 2013, you only have mark as source folder, just like in Eclipse till now we have "add source folder", but now in 2018 it is available in Intellij: you can mark a folder as source, resources, test source, test resources, and all of them will be add to the root of classpath. )
I had the same problem and noticed that the resource file, for example: my.properties is not copied to the corresponding module folder in the target directory after build occurres. In order to solve that, I had to instruct Maven to copy the resources from the module directory to the target directory during the build process. In the .pom file I added <resource> element like that:
<project ...>
...
<build>
...
<resource>
<directory>src/main/java/com/abc/xyz</directory>
<targetPath>com/abc/xyz</targetPath>
</resource>
</build>
...
</project>
Note that the <directory> element is relative to the location of the .pom file , i.e. the root directory of the project, and the <targetPath> element indicates the package name separated by slashes.
from menu Run/edit configuration
in VM option you should add
-Dspring.config.location=path-file
I've tried it in IntelliJ, and it works!
Only solution worked for me:
File -> Project Structure -> Modules -> Dependencies Tab -> + Sign -> JARs or directories -> select resources directory -> Classes

Classpath variable in java

I'm reading a few files in my application and referring to them as new File("src/main/resource/filename") and it works. But when I package the jar with the Maven assembly plugin and run java - jar I get an error, naturally:
Error occured: src\main\resources\UPDATE.txt (The system cannot find the path specified)
Because there is no src/main/resources in the jar, how can I refer to src/main/resources as some kind of classpath variable, so that the application works both in standalone java and in an assembled jar?
You will need to load the file using the Class.getResourceAsStream() method
E.g.
InputStream str = getClass().getResourceAsStream("/UPDATE.txt");
Or if you are in a static method, then specify the class explicitly
InputStream str = MyApp.class.getResourceAsStream("/UPDATE.txt");
EDIT:
With a StreamSource, just pass the input stream into the stream source, e.g.
new StreamSource(getClass().getResourceAsStream("/UPDATE.txt"));
But watch out, getResourceAsStream returns null if the resource doesn't exist, so you might want to explicitly check for that and throw an exception.
The src/main/resources is a development time convention followed by maven projects to place artifacts other than source code. Once the jar has been build they are added to the classpath. So in your e.g. scenario the UPDATE.TXT is at the root of the classpath.
So you should be referring to the resources from the classpath and not from the file-system. http://mindprod.com/jgloss/getresourceasstream.html

Categories

Resources