load resources depending on maven profile - spring-boot

I try to ask the question in simpler form.
I have a multitier SpringBoot 2.2.6 using maven 3.6, Spring Tool Suite 4 as follows:
main-project
- common-layer (packaging jar)
- service-layer (packaging jar)
- web-layer (packaging war)
- src/main/resources
- application.properties
- application-dev.properties
- application-customer1.properties
- config.properties
parentpom.xml
In my parentpom.xml I have several profile depending on customer I building for:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profile>[some spring profile]</spring.profile>
<active.profile>dev</active.profile>
</properties>
</profile>
<profile>
<id>customer1</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<spring.profile>[some spring profile]</spring.profile>
<active.profile>customer1</active.profile>
</properties>
</profile>
</profiles>
I also have a resource loader in my build section of web-layer pom.xml because for the 90% of profile this is the required configuration:
<build>
<finalName>${war.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>application-${active.profile}.properties</include>
<include>application.properties</include>
</includes>
</resource>
</resources>
</build>
Now suppose that for the customer X I don't want to bring inside my package no properties file, can I do it in parent.pom?
I'll try with something like:
<profile>
<id>X</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- <spring.profile>[some spring profile]</spring.profile> passing it from command line -->
<active.profile></active.profile>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>application.properties</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
But doesn't work.

Related

How to update properties file using pom.xml through command line

This is my properties file where i have added this variable
databaseEnabled=${db.activedb}
Path of my properties file
src/main/resources/application-dev.properties
This is my pom.xml where I have added this code
<build>
<finalName>spring-boot</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>dynamo</id>
<activation>
<property>
<name>env</name>
<value>dynamo</value>
</property>
</activation>
<properties>
<db.activedb>dynamodb</db.activedb>
</properties>
</profile>
<profile>
<id>mongo</id>
<activation>
<property>
<name>env</name>
<value>mongo</value>
</property>
</activation>
<properties>
<db.activedb>mongodb</db.activedb>
</properties>
</profile>
</profiles>
Add includes tag:
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>/application-dev.properties</include>
</includes>
</resource>
</resource>
To set profile using -P option:
mvn package -P mongo
To check result open target/classes/application.properties file.

Jenkins cannot build maven with [0.0.1,)

I'm trying to run the build of a project, which has as dependence, a jar of my own.
Code dependency:
<profile>
<id>local-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>ambient</name>
<value>local</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.enterprise</groupId>
<artifactId>enterpriseUtil</artifactId>
<version>[0.0.1,)</version>
</dependency>
</dependencies>
<build>
<finalName>${finalName}</finalName>
<resources>
<resource>
<directory>src/main/resources_local</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin-version}</version><!--$NO-MVN-MAN-VER$ -->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin-version}</version><!--$NO-MVN-MAN-VER$ -->
<configuration>
<attachClasses>true</attachClasses>
<warSourceExcludes>META-INF/context.xml</warSourceExcludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
The strangest thing is that a local build succeeds, even if I exclude the dependency from my .m2, and download from my nexus
The error:
No versions available for com.enterprise:enterpriseUtil:jar:[0.0.1,) within specified range -> [Help 1]

Maven multi-module multi-profile project with shared resources

I'm trying to have my resources copied into a classpath depending on which profile was selected using maven. My resources folder structure is as following:
src/main/resources:
config
production
development
staging
My current not-working config is
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>envtype</name>
<value>dev</value>
</property>
</activation>
<build>
<finalName>Corelay</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<excludes>
<exclude>**/production/**</exclude>
<exclude>**/staging/**</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<excludes>
<exclude>**/production/**</exclude>
<exclude>**/staging/**</exclude>
</excludes>
</testResource>
</testResources>
</build>
</profile>
In hibernate configuration file under config/hibernate/hibernate-config.xml i request some properties from same package
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:**/jdbc.properties</value>
<value>classpath*:**/hibernate.properties</value>
</list>
</property>
</bean>
but there is an error:
Could not resolve placeholder 'jdbc.driverClassName' in string value "${jdbc.driverClassName}"
this property is defined in that file. What's wrong? And another question is how to make resources copied from those profile folders appear in exactly same output classpath structure? I mean there should be no /production, /development or /staging : just /env
I know I could just put them into separate in but then if there are shared ones (like config in the presented structure) how could I include it too?
Create a folder src/main/config at the same level as src/main/resources. Inside create 3 sub-folders common, dev and production:
|__common
| |__common.properties
|__dev
| |__dev.properties
|__prod
| |__prod.properties
Then configure two profiles, dev and production:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/config/common</directory>
</resource>
<resource>
<directory>src/main/config/dev</directory>
</resource>
</resources>
</build>
</profile>
<profile>
<id>prod</id>
<build>
<resources>
<resource>
<directory>src/main/config/common</directory>
</resource>
<resource>
<directory>src/main/config/prod</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
With this, mvn clean install copies common.properties and dev.properties to the root of the classpath, as the dev profile is active by default.
mvn clean install -Pprod will then install common.properties and production.properties, but no dev.properties, and also to the root of the classpath.

Directory filtering Maven

I want to filter directory and its content based on profile. Here is my pom.xml:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<targetPath>properties</targetPath>
</resource>
</resources>
<filters>
<filter>src/main/resources/${env}/ucm.properties</filter>
</filters>
</build>
<profiles>
<profile>
<id>int</id>
<properties>
<env>int</env>
</properties>
</profile>
<profile>
<id>uat</id>
<properties>
<env>uat</env>
</properties>
</profile>
<profile>
<id>stag</id>
<properties>
<env>stag</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>
And this is my project structure:
But when it is building the jar it is copying all the folders (int, uat, stag, prod) inside it.
How can I solve the issue?
You need to add section in your resource declaration. Like that:
...
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<targetPath>properties</targetPath>
<includes>
<include>${env}/*</include> <!-- including only the associated profile dir -->
<include>env.properties</include>
</includes>
</resource>
...
I don't know if the ${env} property will work there, else maybe ${project.activeProfiles[0].id} will work
See http://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html for more info

Maven 3 profile with extensions

My question had been addressed in this thread, but the explanation is not clear.
I have this build definition in one of my pom.xml files:
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
Notice that I'm using the maven-s3-wagon extension.
Next, I would like to have 2 different profiles, each with it's own settings, plugins and extensions but maven does not allow the extensions tag under a profile.
When I try using a profile:
<profiles>
<profile>
<id>local-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
I get a an error in my pom:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'extensions'. One of '{"http://maven.apache.org/POM/4.0.0":defaultGoal, "http://maven.apache.org/POM/
4.0.0":resources, "http://maven.apache.org/POM/4.0.0":testResources, "http://maven.apache.org/POM/4.0.0":directory, "http://maven.apache.org/POM/4.0.0":filters, "http://
maven.apache.org/POM/4.0.0":pluginManagement}' is expected.
Question So using the extension tag means I can't use profiles? How can I use or change build extensions via profile?
Indeed, the official Maven POM reference is not clear about the possible usage of extensions as part of a Maven profile, since it states you can have a build element within it, but not what of the build section.
However, the official Maven model effectively filters and provides what of the build section you can actually use within a profile section. And indeed extensions is not there.
However, what are Maven extensions? Build/Lifecycle enhancement, but also (and essentially): a library added to the runtime classpath of the Maven build, which participates to the build, but it is not packaged with the final artifact.
Hence, in such a scenario (if you need to have extensions in profile or have a profile to change/add an extension) you could use the following trick:
Have an harmless extension as default extension of your build (where harmless means whatever library which could be part of your build classpath and essentially not affect it at all)
Have properties defining the GAV coordinates (GroupId, ArtifactId, Version) of this extension
Have a profile which overrides these properties with the desired (useful) extension
As an example, given the following sample POM:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.11</extension.version>
</properties>
<build>
<extensions>
<extension>
<groupId>${extension.groupId}</groupId>
<artifactId>${extension.artifactId}</artifactId>
<version>${extension.version}</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>customize-extension</id>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.12</extension.version>
</properties>
</profile>
</profiles>
</project>
The default build (without the customize-extension profile activated), would use the default defined properties and as such add junit as build extension: this is harmless (although it may create conflicts with another junit version of your build, so make sure you use the same version of use an even more harmless library for that).
You can check Maven will pick it up by running a really first build phase, just to check information in our case, and enable the debug flag:
mvn initialize -X
And checking as part of the build log:
[DEBUG] Populating class realm extension>junit:junit:4.11
[DEBUG] Included: junit:junit:jar:4.11
Now let's use our trick: let's add (change) a build extension via profile:
mvn initialize -X -Pcustomize-extension
And as part of our build log we would have:
[DEBUG] Populating class realm extension>junit:junit:4.12
[DEBUG] Included: junit:junit:jar:4.12
Bingo. Maven picked up a different extension (in this case, a different version, the 4.12) and we succeeded on changing (or actually adding a meaningful) build extension via profile.
Just a crazy idea: use modules
Define a parent pom like this:
<groupId>org.example</groupId>
<artifactId>my-parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>use-pom1</id>
<modules>
<module>pom1</module>
</modules>
</profile>
<profile>
<id>use-pom2</id>
<modules>
<module>pom2</module>
</modules>
</profile>
</profiles>
Define the desired extensions on pom1 and pom2.
I think the solution is here http://maven.apache.org/guides/mini/guide-using-extensions.html
Define a build section where extensions are defined and then into the profile set the attribute true ( like in the second profile shown below )
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.9</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>create-default</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>create-core</id>
<activation>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<extensions>true</extensions>
<version>2.6</version>
<configuration>
<finalName>import-station-core-${project.version}</finalName>
</configuration>
<executions>
<execution>
<id>make-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

Resources