Placeholders in properties file are not replaced when executing maven install goal - java

I would like to configure a properties files depending on a profile, either ´dev´ or ´prod´, however the placeholders in the properties file are not replaced when executing the maven install goal.
Here is the pom file:
<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>abc.myproject</groupId>
<artifactId>myartifact</artifactId>
<packaging>war</packaging>
<version>0.1.0-SNAPSHOT</version>
<name>projectname</name>
<description>Site Description</description>
<url>http://www.myproject.abc</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven-war-plugin.version>2.4</maven-war-plugin.version>
<tomcat-deploy-path>output</tomcat-deploy-path>
</properties>
<dependencies>
// various dependencies
</dependencies>
<build>
<finalName>v${project.artifactId}#${project.version}</finalName>
<filters>
<filter>src/main/resources/profiles/${build.profile.id}/mongo.properties</filter>
</filters>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<outputDirectory>${tomcat-deploy-path}</outputDirectory>
<failOnMissingWebXml>true</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
</profiles>
</project>
The placeholder mongo.properties file:
database.name=${database.name}
database.port=${database.port}
database.host=${database.host}
database.username=${database.username}
database.password=${database.password}
The profiles/dev/mongo.properties file:
database.name=mydatabase
database.port=27017
database.host=localhost
database.username=root
database.password=psw1
The directory structure is as follows:
> myproject
pom.xml
> src
> main
> java
> resource
> profiles
mongo.properties
> dev
mongo.properties
> prod
mongo.properties
> webapp
> test
I followed the instructions in this blog article: http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

I just tested your setup and it worked correctly: the file WEB-INF/classes/mongo.properties was correctly replaced.
The problem you are having revolves around the fact that you are outputting the final war inside a folder that is not under target. This is a very bad idea. Currently, the final WAR is generated inside the directory output, which corresponds to the property tomcat-deploy-path in your POM.
<tomcat-deploy-path>output</tomcat-deploy-path>
The big problem with such a setup is that running mvn clean will not delete that directory and subsequent builds won't override it, meaning the WAR will never be updated and you will keep an old obsolete WAR. I strongly suggest that you move this property under the Maven build directory, something like
<tomcat-deploy-path>${project.build.directory}/output</tomcat-deploy-path>
so that it is properly cleaned when running mvn clean.
As such, to resolve your problem, you should manually delete the folder output and rerun mvn clean install. It should generate a proper and new WAR.

Try using #..# instead of ${}, for example
database.name=#database.name#
For more info refer to: https://docs.spring.io/spring-boot/docs/1.4.x/reference/html/howto-properties-and-configuration.html

Related

Maven Compile cant find src/main/resources directory

I am trying to setup an integration-test environment using Maven for my project but am getting the below error when I run the Compile goal.
[ERROR] Failed to execute goal
org.apache.maven.plugins:maven-resources-plugin:3.0.2:resources
(default-resources) on project mavenintegrationtest: Error loading
property file
'/Users/xxx/dev/poc/java/mavenintegrationtest/profiles/dev/config.properties'
-> [Help 1]
The error seems to be complaining that it cant find the config.properties file in that location which is correct. For some reason it has removed the "src/main/resources" bit from the file path.
So the correct full path is,
/Users/xxx/dev/poc/java/mavenintegrationtest/src/main/resources/profiles/dev/config.properties
but for some reason its removed src/main/resources and so is looking in,
/Users/xxx/dev/poc/java/mavenintegrationtest/profiles/dev/config.properties
Does anyone know whats causing this ?
My POM is as shown below and I get this error when I uncomment the following "filter" tag,
<filter>${basedir}/profiles/${build.profile.id}/config.properties</filter>
I've tried removing the ${basedir} statement and still get the same error.
<?xml version="1.0" encoding="UTF-8"?>
<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.stackoverflow</groupId>
<artifactId>mavenintegrationtest</artifactId>
<version>1.0-SNAPSHOT</version>
<name>mavenintegrationtest</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<filters>
<filter>${basedir}/profiles/${build.profile.id}/config.properties</filter>
</filters>
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
<!-- Profile configuration -->
<profiles>
<!-- The configuration of the development profile -->
<profile>
<id>dev</id>
<!-- The development profile is active by default -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<!-- The configuration of the integration-test profile -->
<profile>
<id>integration-test</id>
<properties>
<build.profile.id>integration-test</build.profile.id>
</properties>
</profile>
</profiles>
</project>
The filter (link) element will parse your files and apply a content filter on them.
The profiles (link) element helps you define different environments for the build.
All of this as to do with your resources. These can be configuration files, or other type of files. If you filter then you can change the content of this files with other values - e.g. pom properties. When using profiles you can have different replacement properties for each environment.
You should move the profiles up in the tree for the default path, or add a configuration in your pom for the resource location.
The base dir is the folder containing your pom. You should have your profile folder here.
Also, here is some good information about profiles and its configurations.

In maven, how to name war file different in release than in snapshot build

I'm using the maven-war plugin. I've also looked at the maven-versions plugin. In neither case do I see how to give a different name to a snapshot build than a release build.
I've seen examples using profiles but the docs seem to indicate that the use of profiles in the pom.xml is not a good idea.
How should this be done?
Try the below
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>src\main\webapp\WEB-INF\web.xml</webXml>
<classifier>${envClassifier}</classifier>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>snapshot</id>
<properties>
<envClassifier>snapshot</envClassifier>
</properties>
</profile>
<profile>
<id>release</id>
<properties>
<envClassifier>release</envClassifier>
</properties>
</profile>
</profiles>
Now, run command mvn clean install -Psnapshot Or mvn clean install -Prelease to get your desired artifacts. Hope this helps
You can control final war file name by warName attribute

How to specify in Maven extra source/resource folders so IDEs are aware of them?

I'm a Maven beginner, and after some trial and error, I managed to specify different properties files for the release WAR with respect to the development WAR (I tried to do it in the simplest way I could think of, but feel free to suggest any simpler solution).
So, during development, my database.properties and log4j.properties come from src/main/resources, while producing the release WAR they come from src/main/resources/release.
So far, so good.
The question is: since I'm working with Eclipse, is there a way to say, inside the POM, that the src/main/resources/release is a source folder too, so that Eclipse will list it under the other source folders in the Project Explorer, even when another developer imports the project inside his IDE (i.e. without adding that folder as a source folder manually)?
This is the relevant part of my POM:
<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>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<war-name>/</war-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
...
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
...
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
...
</plugin>
</plugins>
</build>
<dependencies> ... </dependencies>
<profiles>
<profile>
<id>release</id>
<properties>
<war-name>ROOT</war-name>
</properties>
<build>
<resources><!-- Replace Maven default resources directory (this could probably be achieved with a property)-->
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources/release</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
...
< sourceDirectory > src/main/java </ sourceDirectory >
< testSourceDirectory > src/test/java </ testSourceDirectory >
< resources >
< resource >
< directory > src/main/resources </ directory >
</ resource >
</ resources >
< testResources >
< testResource >
< directory > src/test/resources </ directory >
</ testResource >
</ testResources >
...
</build>
You can specify the profile that eclipse should run maven in...
Right click on project, select Maven, and include the profiles you can eclipse to work under.
Your config should be picked up by eclipse when you do a maven update project (i.e. eclipse should recognise the new source folders) once you've changed the profile.
Here's how I did it.
Basically, I declare all the resources folders I want to see in Eclipse in the default configuration (adding them in each profile didn't work since when a profile is active, the <resources /> node is appended to the final POM instead of (as I thought) replacing the existing one); then I tell Maven from which folder to copy the resources using properties, whose values are driver by the active profile.
Any comment is, of course, very much appreciated!
<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>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>war</packaging>
<name>...</name>
<!-- My prerequisite was that when working in Eclipse no extra steps
should be required to make the IDE use the right configuration than
Configure -> Convert to Maven Project, so I didn't like having
default settings in a profile that must be enabled in Eclipse project
configuration -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<war-name>/</war-name>
<!-- These solve the problem: AFAICT, each <resource /> is added to the final POM,
so declaring a resources folder in a profile didn't exclude other resources
folders declared in the default (i.e. without profiles active) configuration.
So, the solution is to change what Maven brings in from each folder depending
on the profile currently active. What follows is the default, no-profile
active configuration. -->
<res.devel.includes>**/*</res.devel.includes>
<res.devel.excludes></res.devel.excludes>
<res.local.includes></res.local.includes>
<res.local.excludes>*</res.local.excludes>
<res.release.includes></res.release.includes>
<res.release.excludes>*</res.release.excludes>
</properties>
<build>
<resources><!-- Here I declare all the resources folders, so that they will all be shown in Eclipse. Property values drive what is included and excluded. -->
<resource><!-- This is the default Maven main resource directory -->
<directory>${basedir}/src/main/resources-local</directory>
<filtering>true</filtering>
<includes>
<include>${res.devel.includes}</include>
</includes>
<excludes>
<exclude>${res.devel.excludes}</exclude>
</excludes>
</resource>
<resource><!-- This is the resources directory for when the WAR is deployed on a local standalone Tomcan installation (useful for web pages editing) -->
<directory>${basedir}/src/main/resources-local</directory>
<filtering>true</filtering>
<includes>
<include>${res.local.includes}</include>
</includes>
<excludes>
<exclude>${res.local.excludes}</exclude>
</excludes>
</resource>
<resource><!-- This is the resource directory for when the WAR will be deployed -->
<directory>${basedir}/src/main/resources-release</directory>
<filtering>true</filtering>
<includes>
<include>${res.release.includes}</include>
</includes>
<excludes>
<exclude>${res.release.excludes}</exclude>
</excludes>
</resource>
</resources>
<plugins>
<!-- Plugins configurations -->
</plugins>
</build>
<dependencies>
<!-- Dependencies declarations -->
</dependencies>
<profiles><!-- Here are the profiles. When working in Eclipse no profile is active, so the resources will be taken only from src/main/resources (as per default properties values). -->
<profile>
<id>local</id><!-- This is for when the WAR is deployed on a local standalone Tomcat instance (i.e. outside of Eclipse) -->
<properties>
<war-name>ROOT</war-name>
<!-- The resources will be taken only from src/main/resources-local -->
<res.devel.includes></res.devel.includes>
<res.devel.excludes>*</res.devel.excludes>
<res.local.includes>*</res.local.includes>
<res.local.excludes></res.local.excludes>
<res.release.includes></res.release.includes>
<res.release.excludes>*</res.release.excludes>
</properties>
</profile>
<profile>
<id>release</id><!-- This is for when the WAR is deployed on the production server -->
<properties>
<war-name>ROOT</war-name>
<!-- The resources will be taken only from src/main/resources-release -->
<res.devel.includes></res.devel.includes>
<res.devel.excludes>*</res.devel.excludes>
<res.local.includes></res.local.includes>
<res.local.excludes>*</res.local.excludes>
<res.release.includes>*</res.release.includes>
<res.release.excludes></res.release.excludes>
</properties>
</profile>
</profiles>
</project>

Use specific xml files in production vs development

We have a maven based Spring Web-Application. All the web-calls are Restful and need authentication. But for development purpose, it is a pain to do all the needful. So for the development cycle, it is preferred to not have any security.
Using a maven flag or something, how do we generate separate builds for production and development?
All the security related stuff are in web.xml and applicationContext.xml. We can have 2 copies (one for development and the other for production). In the maven build, what is the simplest way to include the necessary files and omit others.
PS: I have seen examples of doing above using assembly plugin. I do not need all that but just a simple way to do it. I am using maven-war-plugin to generate war file.
Use profiles. You define them in your pom.xml (see below) and then when you build you include them. For command line this is simply
mvn -P <profile> <target>
most IDE's provide a way to set a profile.
pom.xml:
<properties>
<!-- default -->
<webXmlPath>src\main\webapp\WEB-INF\web-test.xml</webXmlPath>
</properties>
<profiles>
<profile>
<id>Production</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}</finalName>
</build>
</profile>
<profile>
<id>Accept</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web-accept.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}-accept</finalName>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webXml>${webXmlPath}</webXml>
</configuration>
</plugin>
</plugins>
</build>

Using Maven To Add Root Path

I am using the copy-maven-plugin provided by com.github.goldin. I want to copy some files through Maven.
However, I don't want to hard code the path as the drive will be different. For example:
<build>
<plugins>
<plugin>
<groupId>com.github.goldin</groupId>
<artifactId>copy-maven-plugin</artifactId>
<version>0.2.5</version>
<executions>
<execution>
<id>create-archive</id>
<phase>test</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<resources>
<resource>
<targetPath>/../src/Server-Parent/src/test/resources</targetPath>
<file>/../src/Server-Parent/DB/src/test/resources/mongoDB.xml</file>
<destFileName>mongoDB.xml</destFileName>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
When I hard code for example, C:\folder name\src\Server-Parent\src\test\resources it works perfectly from any Maven project. However as soon as I put ../src or /../src it contains problems.
Any ideas how I can fix this?
[ERROR] Failed to execute goal com.github.goldin:copy-maven-plugin:0.2.5:copy (c reate-archive) on project Server-Parent: Processing <resource> [Target p ath(s) [/../src/Server-Parent/src/test/resources], directory [C:/folder name\src/Server-Parent/DB/src/test/resources], dependencies []] fa iled with [java.lang.AssertionError]: [C:\folder name\src\Server-Parent\DB\sr c\test\resources] does not exist. Expression: d.directory -> [Help 1] [ERROR]
EDIT 2:
What I am trying to achive:
I have Server-Parent which is pom.xml containing pom value. Inside this is another Server-SubParent containing pom.xml pom value. Now inside this is Server-SubFunctionality containing jar.
Accoriding to your answer how can this be achived:
${project.basedir}
This are three projects where the Server-SubParent is a module of Server-Parent, but Server-SubParent is another pom containing another module containing the real functionality.
Server-Parent
<modelVersion>4.0.0</modelVersion>
<artifactId>Server-Parent</artifactId>
<packaging>pom</packaging>
<name>Server-Parent</name>
<modules>
<module>Server-Sub-Parent</module>
</modules>
Server-SubParent
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.server</groupId>
<artifactId>Server-Parent</artifactId>
<version>S06B1-RELEASE</version>
</parent>
<artifactId>Server-Sub-Parent</artifactId>
<packaging>pom</packaging>
<name>Server-Sub-Parent</name>
<modules>
<module>Server-Sub-ParentFunctionality</module>
</modules>
Server-Sub-Parent-Functionality
<parent>
<groupId>com.server</groupId>
<artifactId>Server-Sub-Parent</artifactId>
<version>S06B1-RELEASE</version>
</parent>
<artifactId>Server-Sub-Parent-Functionality</artifactId>
<packaging>jar</packaging>
<name>Server-Sub-Parent-Functionality</name>
Try using maven predefined variables.
<resource>
<targetPath>${project.basedir}/../src/Server-Parent/src/test/resources</targetPath>
<file>${project.basedir}/../src/Server-Parent/DB/src/test/resources/mongoDB.xml</file>
<destFileName>mongoDB.xml</destFileName>
</resource>
Some helpful variables
${project.basedir}
${project.build.directory}
${project.build.sourceDirectory}
more info here

Categories