Resources and config loading in maven project - java

I'm using Maven for desktop build application. I read about Maven standard directory layout and I have this project structure for now:
App
|-- pom.xml
`-- src
|-- main
|-- java
| `-- java classes
|-- resources
| `-- images
| `-- app images
`--config
`--config.xml
I want to find a way to load my resources and config files. I read some articles and topics and found this (simplified example from my code):
//class for loading config
public class Preferences {
public Preferences() {
InputStream image = Preferences.class.getResourceAsStream("images/image.png");
InputStream config = Preferences.class.getResourceAsStream("config.xml");
}
}
But image and config variables contains null. I was trying different variants of loading (from root folder, with this.getClass() instead of Preferences.class, and others), but it's always null. I really don't understand this resource loading system and I didn't find any good documentation about it. It would be nice, if somebody gives a good explanation about this mechanism (or just give a link on docs).
So, the main question is: How can I load my resources and config files?

You can use getResourceAsStream() method of java.lang.Class as you have done, but you have to add / before the path.
This question is tricky.
1. Two methods with same name
First of all, exist two methods of same name and same signature in these two classes:
java.lang.Class
java.lang.ClassLoader
They have the same name: getResource(String) (and getResourceAsStream(String) is alike).
2. They accept params of different format
Then, the param of them has different format:
The method java.lang.Class.getResouce<asStream>() accepts path with and without the leading /, resulting in different resources searching strategies. If a path has no /, Java will search the resource in the package/folder where the .class file resides. If it has /, Java will begin the searching from classpath root.
The method java.lang.ClassLoader.getResource<asStream>() accepts only path without /, because it always search from classpath. In a classpath based path, / is not a valid character. *
*: As this answer states: this.getClass().getClassLoader().getResource("...") and NullPointerException
How to add a folder to classpath? In Eclipse we resolve to the context menu of a project: "Build path" - "Configure build path..." and add some folder to build path.
3. When it comes to Maven
At last, if a project is a Maven project, by default src/main/resources is in the classpath, so we can use
Class.getResource("/path-to-your-res");
or,
ClassLoader.getResource("path-to-your-res");
, to load anything under src/main/resources.
If we want to add another resources folder, as you have mentioned, it is done in pom.xml. And they are added into classpath as well, done by Maven. No extra config is needed.
4. Example
For example, if your config.ini is under src/main/resources/settings, myAvatar.gif under src/main/images, you can do:
In pom.xml:
<build>
<resources>
<resource>
<directory>src/main/images</directory>
</resource>
</resources>
</build>
In code:
URL urlConfig = MyClass.class.getResource("/settings/config.ini"); //by default "src/main/resources/" is in classpath and no config needs to be changed.
InputStream inputAvatar = MyClass.class.getResourceAsStream("/myAvatar.gif"); //with changes in pom.xml now "src/main/images" is counted as resource folder, and added to classpath. So we use it directly.
We must use / above.
Or, with ClassLoader:
URL urlConfig = MyClass.class.getClassLoader().getResource("settings/config.ini"); //no leading "/"!!!
InputStream inputAvatar = MyClass.class.getClassLoader().getResourceAsStream("myAvatar.gif"); //no leading "/"!!!

I think I found the solution. As Juned Ahsan and mR_fr0g write, I need to use ClassLoader class, instead of this.getClass().getResource(). But, it works only for resource folder. But maven allows to add other folders as resource folders. I was just needed to add this section to pom.xml:
<build>
<resources>
<resource>
<directory>src/main/config</directory>
</resource>
</resources>
</build>
And working java code is:
InputStream image = this.getClass().getClassLoader().getResourceAsStream("images/image.png");
InputStream config = ClassLoader.getSystemResourceAsStream("config.xml");

public Preferences() {
InputStream image = this.getClass().getClassLoader().getResourceAsStream("image.png");
InputStream config = this.getClass().getClassLoader().getResourceAsStream("config.xml")
}

How about using this appraoch:
InputStream file = ClassLoader.getSystemResourceAsStream("res.txt");
or
InputStream file = Thread.currentThread().getContextClassLoader().getResourceAsStream("MyProperty.properties");
As you currently have it there, that will look for the MyProperty.properties file at the top of your classpath. The could be in your src/main/resources directory or other src folder -- it would depend on how your application (jar/war) is built.
If you are building a jar then you should be able to unpack it and see your properties file at the top level of the jar. If you are building a war, maybe it should be in the WEB-INF/classes directory. Again, it depends on how it was built.

Try to build the project before.
If you just put the files in the resources folder then you need to build the project in order to copy the new resource files into target folder

It's an old answered question, but I found that you need to use the include tag set or it won't find the resource when you call.
ClassLoader.getSystemResource("config.xml").
I'm using the latest maven (Oct 2020) on JDK14
Here's the working xml. Hope it helps as I tried it as stated in the solution here and it would not work until my xml looked as follows.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<!-- or whatever other file extensions you want to include -->
</includes>
</resource>
</resources>
</build>

Related

Best Practices on refering to resource files in Java code by relative path?

I have a repository which looks something like this:
/
/resources/resource1.txt
/resources/resource2.txt
/code/
/code/C/...
/code/java/pom.xml
/code/java/src/main/XYZ.java
/code/java/src/main/ABC.java
In other words, there is a maven project rooted in /code/java/, and there are resource files located at /resources/.
Now, I want to refer to the resource files in my code. The code will be something like the files in /code/java/src/main/XYZ.java. How should I refer to this file?
I do not want to hard code the filepath from my local machine. For example, I do not want something like /Users/agnishom/projectX/resources/resource1.txt. This will make it difficult for other people who clone my repository to make it work.
I would like to be able to name a file by their relative path, possibly relative to the pom.xml file.
What is the best way to do this? Moving the resource files into the /code/java/ is not an option because they are shared by other projects which are not part of the java
In the build section of your pom.xml, you can specify the resources directory relative to the project's base directory (/pom.xml), as you were suggesting:
<build>
...
<resources>
<resource>
<targetPath>.</targetPath>
<directory>${basedir}/../../resources</directory>
</resource>
</resources>
</build>
targetPath is the path to where included resources should be placed, relative to the jarfile/resulting build.
directory is the directory to include resources from.

JLabel icon not imported correctly on Java with Maven project

I am making a project on the GUI library system. My IDE is Netbeans. Before I was setting Jlabel icon images from external folders but I want the images to be loaded from the project folder so I imported the images to my project folder from NetBeans 'import to project' option. When i compiled the program it shows 'NullPointerException' in Jlabelxxx.setIcon(). This means it is not loading images from my package/folder. I know what null pointer exception is :). My code is totally fine but I don't know why images are not loading from the project folder.
I am using Netbeans GUI for making Jswing design. My directory structure is shown below:
Project absolute path: C:\Users\nisha\Documents\NetBeansProjects\LibraryManagementSystem
Images absolute path: C:\Users\nisha\Documents\NetBeansProjects\LibraryManagementSystem\src\main\java\gpjlibrarymanagementsystem\icons
I have 2 packages in the "LibraryManagementSysten" project folder. Below it i have 3 packages "" "gpjlibrarymanagementsystem" "gpjlibrarymanagementsystem.icons". The default package has nothing. The second one has JFrame files and the last one have images. Please watch the image posted above to understand my directory structure.
I have tried to make different directories in the same project but it's not working.
Examples of code where I am getting 'NullPointerException':
lblMinimize.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gpjlibrarymanagementsystem/icons/icons8-minus-24.png")));
lblMaximize.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gpjlibrarymanagementsystem/icons/icons8-maximize-button-20.png")));
lblClose.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gpjlibrarymanagementsystem/icons/icons8-multiply-24.png")));
You can see, as per my directory structure, my code is right.
I have solved this problem. The images should be added to the resources folder which is: yourprojectname\src\main\resources. In my case: LibraryManagementSystem\src\main\resources\icons. All image files are in icons folder :)
In maven the file structure should look like this:
> Project |-- pom.xml `-- src
> `-- main
> `-- resources
However, all your resources may not be in src/main/resources. Thus, you'd have to specify those directories by adding the following to your POM.
<project>
...
<build>
...
<resources>
<resource>
<directory>[your folder here]</directory>
</resource>
</resources>
...
</build>
...
</project>
So if your resources reside in src/my-resources
Project
|-- pom.xml
`-- src
`-- my-resources
you can specify that directory by doing the following:
...
<resources>
<resource>
<directory>src/my-resources</directory>
</resource>
</resources>
...
Furthermore, you can have several directories by adding multiple elements:
...
<resources>
<resource>
<directory>resource1</directory>
</resource>
<resource>
<directory>resource2</directory>
</resource>
<resource>
<directory>resource3</directory>
</resource>
</resources>
...
One or more of:
/gpjlibrarymanagementsystem/icons/icons8-minus-24.png
/gpjlibrarymanagementsystem/icons/icons8-maximize-button-20.png
/gpjlibrarymanagementsystem/icons/icons8-multiply-24.png
is wrong (the file does not exist), hence getResource returns null.
The project directory name (see below) is icon (singular) but the code says icons (plural).
Put the images in a folder called "resources", the path should be:
src / main / resources / image.jpg
Now in Netbeans click on "Clean and Build Project"
Create a label and with the help of the IDE put an icon, for that go to the label properties.
Once this is done, right click on the label and click on "Custom code" and put in a "try catch" the part where the icon is placed on the label.
It worked for me and it took me a day to figure out how to do it.
I was suffering this changes.
I was using Packages... the package with icon Open.png was bz.usedPictures
button.setIcon(
new javax.swing.ImageIcon(
getClass().getResource("/bz/usedPictures/Open.png")
)
);
I was migrating to maven.
According to Maven:
https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
src/main/resources: Application/Library resources
Then I put the ICON in this Location:
PROJECTNAME\src\main\resources\usedPictures\
--Open.png
Clean and Build. And you can check here the location where the file will be get....
PROJECTNAME\target\classes\usedPictures\
--Open.png
Now the Example using the ICON:
button.setIcon(
new javax.swing.ImageIcon(
getClass().getClassLoader().getResource("usedPictures/Open.png")
)
);

Cannot get my features files recognized by aws device farm

I am having an issue running my cucumber project with device farm.
I am getting this error:
[TestNG] Caused by: java.lang.IllegalArgumentException: Not a file or directory: /tmp/scratchheDEgq.scratch/test-packagex5ZhYf/src/test/java/cucumber/features
I understand from this message that there is an issue with the path of the features directory in my project but locally it works.
This is how I put it in my code:
#CucumberOptions(features = "src/test/java/cucumber/features", glue = "cucumber.steps")
Should I provide a different path to device farm? What am I missing here?
Thanks
By default the src/test/java/cucmber directory(if it exists in the project) is not included the *-test.jar file. Try putting the feature files in the src/test/resources directory as shown in the Device Farm sample project.
https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/tree/master/src/test/resources/LoginTest
Alternatively, you can implement the testResources tags in the pom.xml to explicitly reference another directory besides src/test/resources assuming that we're using maven:
<testResources>
<testResource>
<directory>${project.basedir}/src/test/YOUR_DIRECTORY_HERE</directory>
</testResource>
</testResources>
Check out this link for more info on the testResources tag
https://maven.apache.org/pom.html#Resources
testResources: The testResources element block contains testResource elements. Their definitions are similar to resource elements, but are naturally used during test phases. The one difference is that the default (Super POM defined) test resource directory for a project is ${basedir}/src/test/resources. Test resources are not deployed.
HTH
-James

Java path to file in src/main/resources

I have a maven module with the following directory structure and I want to get the path to abc.access in abcManager.java.
src
|-main
|-java
|-org.abc.xyz
|-init
|-abcManager.java
|-resources
|-abc.access
I tried it using abcManager.class.getResource("abc.access") but it gives a null.
I went through the below questions but the solutions didn't work.
How to get the path of src/test/resources directory in JUnit?
Can't get path to resource
The problem was that I have not included the resource in the maven build in pom file. When I included the following it worked with abcManager.class.getResource("/abc.access")
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>abc.access</include>
</includes>
</resource>
</resources>
</build>
According to the javadoc of URL java.lang.Class.getResource(String name) :
Before delegation, an absolute resource name is constructed from the
given resource name using this algorithm:
If the name begins with a '/' ('\u002f'), then the absolute name of
the resource is the portion of the name following the '/'.
Otherwise,
the absolute name is of the following form:
modified_package_name/name
Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').
When you invoke :
abcManager.class.getResource("abc.access")
You don't prefix the path with a "/" character . So, you use the second way.
It means that the resource should be located in
the org.abc.xyz.init package (or folder) but it is not the case since the resource is located in the root of the resources folder.
In Maven, resources is the base directory for resources.
So you can get the resource by invoking the first way:
abcManager.class.getResource("/abc.access")
or you can also simply do it :
getClass().getResource("/abc.access")
try this :
String filename = "abc.access";
InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
Following should work.
InputStream resourceAsStream =
abcManager.class.getClassLoader().getResourceAsStream("abc.access");
provided you are working inside an IDE (Ex. Eclipse).
If you are trying this from commandline, you need to explicitely setup the classpath.
class.getResource is local to the class, in this case package org.abc.xyz.init. You are trying to read src/main/resources/org/ABC/xyz/init/abc.access. Alternatively to the class loader which always loads from the classpath root you can also do class.getResource("/abc.access")

Different property files when depend on a library

I have two different projects, A and B. Both projects load their own properties with:
new PropertiesConfiguration("application.properties")
Each application.properties is located in the Maven resource root directory.
When I execute Project B alone, all properties are loaded correctly.
Project A depends on Project B. When I execute Project A, the property class of Project B cannot load the correct properties, because the properties of Project A are loaded.
How can each Project load the correct properties even if they are included as a dependency. I have to specify to load the resources in different contexts, but I don't know how.
My maven settings for resources:
<resource>
<directory>${project.build.sourceDirectory}</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
You probably have some specific packages for Project B like
com.company.packageB
So put your application.properties in
src/main/resources/com/company/packageB/application.properties
And same for the Project A
You can iterate over all application.properties files like this
for (Enumeration<URL> urls = ClassLoader.getSystemResources("application.properties"); urls.hasMoreElements();) {
URL url = urls.nextElement();
}
Depending on your application you have to make a choice how to proceed if multiple property files are found. I hope this helps.

Categories

Resources