Maven - How to work with "*.properties" files after build? - java

I have these folders in my project structure
/src/main/java
/src/main/resources
In the "resources" folder I have 2 files: "config.properties" and "logging.properties".
And I have the following "" in my pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>myapp.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
When I run "mvn clean package", it does generate the "target" folder with the jar and the "classes" folder containg the properties file as mentioned above.
To read one of the properties files (after clicking on a Button), I'm using the following code:
Properties prop = new Properties();
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties"));
String logFolder = prop.getProperty("myApp.property");
//Do something with 'logFolder'
It runs OK.
But if I change the "myApp.property" in "logging.properties" file, the change doesn't affect the "logFolder" value.
What must I do to be able to dinamically change the property value and make my application read the new value WITHOUT RECOMPILING THE PROJECT?
Thank you.

You can invoke respective plugins manually:
mvn resources:resources maven-assembly-plugin:single
Though this is not the best option anyway. It's better to eliminate re-packaging all together for local deploys:
Just start the app in IDE instead of building a JAR. IDE will detect changes in the configs.
And in general allow overriding your variables with either env vars or system variables. So after reading the file also check if the values are overriden and use those.
For remote deploys we usually don't keep configuration files in JAR (you don't want to keep PRD passwords in there, right?). So deploying to remote envs should use config files from restricted sources. This means that the app needs to be able to read configs that are not inside JAR.

Here's what I added to my pom file so Maven loads the resources into the jar at the root level.
<resources>
<resource>
<directory>src/my-resources</directory>
<includes>
<include>**/*.txt</include>
<include>**/*.jpg</include>
</includes>
</resource>
</resources>
</build>
Notice how my folder, called my-resources, is not placed under main, it's placed under src. Of course, without telling Maven about your resource in the pom it won't do anything for you.
I didn't check your code, but there's how to tell Maven to pack your resources into your jar for you. And at a glance at your code, when working from inside a jar, you need to prefix your filename with a '/' because it's now using a relative path, not an absolute path.
getResourceAsStream("logging.properties") works outside a jar.
getResourceAsStream("/logging.properties") is what you need inside a jar.

I managed to solve this issue.
The other answers are correct. The real problem (I think) is with this "maven-assembly-plugin" that I was using to build.
For some reason, it does not read my properties files after build, maybe I was doing something wrong with it.
So, I changed my <build> script in my pom.xml to the following:
<build>
<finalName>myapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>logs</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>myApp.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/logs</include>
<include>**/*.properties</include>
<include>**/*.gif</include>
</includes>
</resource>
</resources>
</build>
In short: I replaced the "maven-assembly-plugin" with "maven-dependency-plugin" (I'm using an Oracle DB in this project), "maven-resources-plugin" (copying all of my resources to "/target" folder after build) and the "maven-jar-plugin" setting the "Class-path" property to ".".

Related

how to create two jars from one Maven project but with different resources files

I have a single maven project that has multiple folders in src/main/resources, I want to generate two Jars, one include src/main/resources/folder1/all properties and the other include src/main/resources/folder2/all properties.
Is their a way to achive this ? If not, what is the simplest way to achive my goal?
If I understood your problem correctly then you can use "Maven Assembly plugin" and "The Assembly Descriptor" in the following way:
first of all, you can not use a profile if you want to build 2 jar files simultaneously.
So, my suggestion is to exclude your config files from your jar then use Maven Assembly plugin to create a different zip file with these folders.
for example, in your case you should have 2 file descriptors like the following:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>folder1</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/java/descriptors/folder1.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
and folder1.xml contains:
<assembly>
<id>folder1</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>
target/${project.artifactId}-${project.version}-yourJar.jar
</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/resources/folder1</directory>
<includes>
<include>*</include>
</includes>
<outputDirectory>/config</outputDirectory>
</fileSet>
</fileSets>
</assembly>
for "folder2" you can do it in the same way.
also for exclude some config files from the jar you can use this plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>package.path.to.your.main.class.MainClass</mainClass>
</manifest>
<manifestEntries>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
Using maven-resources-plugin as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
From Introduction to Build Profiles
Profiles can be activated in the Maven settings, via the section. This section takes a list of elements, each containing a profile-id inside.
<settings>
...
<activeProfiles>
<activeProfile>profile-1</activeProfile>
</activeProfiles>
...
</settings>
Profiles listed in the tag would be activated by default every time a project use it.
Profiles can be automatically triggered based on the detected state of the build environment. These triggers are specified via an section in the profile itself. Currently, this detection is limited to prefix-matching of the JDK version, the presence of a system property or the value of a system property.
This allows to create a different package content based on the target environment.

Maven copy resources

In the resources in the profile folder there is a configuration file, depending on the profile it should be taken and put in the resource root
Actually, what I encountered
He puts it in the project itself, and not in the original jar
When the second time you collect this file already comes
So that the folder itself in the jar does not fall
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<executions>
<execution>
<id>copy-properties</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/profile/${profile.dir}</directory>
<includes>
<include>server.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>${maven-ejb-plugin.version}</version>
<configuration>
<filterDeploymentDescriptor>true</filterDeploymentDescriptor>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<ejbVersion>3.0</ejbVersion>
</configuration>
</plugin>
</plugins>
Tell me where I was wrong?
In which plugin to configure maven-ejb-plugin or maven-resources-plugin
I have src/main/recoursces/profile/
serverA/server.properties
serverB/server.properties
serverC/server.properties
I want jar
- It did not have a folder profile
- and have one server.properties
I'm not sure if I understand your question. I believe the resources phase package is not correct, it should be on a previous one like process-resources.
Here you have the Maven Lifecycle Reference
process-resources: copy and process the resources into the destination directory, ready for packaging.
package: take the compiled code and package it in its distributable format, such as a JAR.

Uber jar not reading external properties files

I am creating an uber jar i.e. jar with dependencies for my project. I have a bunch of properties files that the project uses. I want to be able to change these properties files before running my project so i want them to be outside of the jar. Here is the relevant sections of my pom
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<artifactSet>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.json</exclude>
</excludes>
</artifactSet>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>path.to.main.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.json</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
so essentially, I want to create a folder ${basedir}/target/conf and copy all the .properties and .json files to it. Also, here is how I am reading the files
InputStream in = this.getClass().getClassLoader().getResourceAsStream("filename.properties");
I am facing a couple of problems
When i do mvn clean install, i still see the all the .properties and .json files in the classes folder. Shouldn't they have been excluded?
The conf folder is created with all of the files, but when I run the jar adn try to change the properties, the changes are not picked up. How can i ensure that the conf folder is being added to the classpath?
I want to be able to load the .properties and .json files from the src/main/resources folder while i am developing so i dont want to put them in a separate folder. Is this possible?
I was facing the same issue where Uber jar is not reading the external configuration file.
I tried below configuration and it worked like charm. Refer below configuration it may help someone having the issue with uber jar not reading extenarl files.
I am not sure if this is the best way but haven't found any soultion online :)
I have included the resources using IncludeResourceTransformer.
Using filter removed the properties file from uber jar.
In classpath /conf reading the properties from external folder.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions> <!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
add Main-Class to manifest file
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>JobName</Main-Class>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>src/main/resources/config.properties</resource>
<file>${project.basedir}/src/main/resources/config.properties</file>
</transformer>
</transformers>
<finalName>FinalJarName</finalName>
<filters>
<filter>
<artifact>groupId:artifactId</artifact>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
good luck.

How to create a jar without meta-inf folder in maven?

If I wanted to create a jar file without META-INF nonsense using jar utility I can pass the -M switch, which will:
-M do not create a manifest file for the entries
Note that this is a feature of the jar utility. If I use it, I will get a jar without the META-INF folder and included MANIFEST, basically just an archive of type jar with whatever files/directories I put in it.
How do I do this with the maven-jar-plugin? I need to do this to conform to another process. (They expect a jar with very specific file/folder layout and I cannot have a META-INF folder at the root of the jar file.)
I've got the configuration to create the jar file just right and I don't want to mess with another plugin...
In maven-jar-plugin there is no option to disable creation of manifest folder, but you can disable the maven descriptor directory like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<addClasspath>false</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
If absolutely you want to delete the META-INF folder you can use maven-shade-plugin like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
You can use maven-shade-plugin to achieve the desired effect:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>${project.groupId}:${project.artifactId}</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
The configuration filters out the META-INF directory and includes only the current project so that dependencies are not attached.

how to make a executable jar pick the properties file during time time using maven

Hi i am using maven buil to create an executable jar, i have few properties file. if i place the properties file in
src/main/resources
maven packages them inside the jar itself. I dont want this to happen, instead i want to place the properties file in a folder called conf and i want these properties file to be avalable to the jar during runtime.
The reason why this is because in future the user can have the flexibility to chnage a few property values like port number etc without.
i have pasted the pom.xml below
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hp.nfv</groupId>
<artifactId>DescriptorA</artifactId>
<version>1.0.0</version>
<name>DescriptorA/name>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.abc.Descripto</mainClass>
</manifest>
<manifestEntries>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
the property file i am using is 'utility.properties' which is present in the src/main/resources
i am using this in the java code as below
ResourceBundle locationUtilityProp = ResourceBundle.getBundle("utility", locale);
but when i execute the above pom.xml file, i get a jar file , which on running gives the below error
java.util.MissingResourceException: Can't find bundle for base name utility
when I un jarred the jar file, i found no .properties files in it.
I am completely new to maven so please can anyone help me make this jar pick the properties file from a directory structure other than src/main/resources at run time.
I got this requirement working , and below i have answered in detail so that it can help someone else someday
package structure:
you need to place .properties files inside src/main/resources when doing a maven build
src
|-main/java/com.abc/.java classes
|-main/resources/error.properties
after maven generates a jar file, then create a folder called config and copy all .properties files inside it. and place your jar file in same directory as your config folder as below
example
|-config
-error.properties
|-jar file generated by maven
code to fetch the resources files
static Locale locale = new Locale("en", "US");
static ResourceBundle locationUtilityProp =ResourceBundle.getBundle("error", locale);
pom.xml to create an executable jar file
first tell maven not to include any of properties files present inside src/main/resources
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
now include maven compiler plugin
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
now include the maven assembly plugin to create an executable jar.
in the mention the folder name where you want maven to pick the resource files( in my case error.properties)
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.abc.hello</mainClass>
</manifest>
<manifestEntries>
<Class-Path>config/</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- bind to the packaging phase -->
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
If I got you right, you want to have a portable, configurable jar so you can edit the config without re-packaging. That can be achieved easily by providing the -cp (or -classpath) option with the path to the folder containing yout utility.properties. So the invocation looks like:
java -cp ./conf -jar youApp.jar
assuming that the config is in a conf sub-folder of where the main jar sits.
More on the classpath.

Categories