Maven: profile properties not be picked up when running test - java

In pom.xml, I define a property:
<profile>
<id>local</id>
<properties>
<build.profile.id>local</build.profile.id>
<serverBaseUrl>http://127.0.0.1:8080</serverBaseUrl>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
And the serverBaseUrl was referenced in file application-email.xml:
<bean id="MailService" class="someclass">
<property name="aurl" value="${serverBaseUrl}"/>
</bean>
I expect that, when running test, using IntelliJ IDEA or using Maven test, ${serverBaseUrl} can be pick up from pom.xml automatically. However, it does not work like what I expect.
When not running test, the thing works exactly what I expect.
What's the problem here? Does maven or IntelliJ IDEA won't pick up profile properties when running test by default? How can I pick up profile's properties when I running the test?
Currently, I have a workaround: Define serverBaseUrl=xxx in config.properties and the property is picked up. This is a little ugly what I want to avoid.

This is more like a shot in the dark, I could not test it.
Add the resources tag in the build section of your pom.xml:
<build>
.....
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>application-email.xml</include>
</includes>
</testResource>
</testResources>
....
</build>
I suppose your application-email.xml is inside src/test/resources folder.

Related

maven profile overwrites test resources

I'm trying to make maven profiles which would use two difference DBMS. DBMS configs are stored in maven profiles. Web App gets settings from file connection.properties in src/main/resources. There is also a similar file with same title connection.properties in src/test/resources and this file should be uploaded only during test lyfecycle maven. Then spring core uses the DBMS connection settings specified in connection.properties.
I have problem with maven profile which overwrites resources such as src/test/resources/connection.properties on src/main/resources/connection.properties from test directory when test lifecycle maven is running.
<profile>
<id>profile-postgres</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<database.driver_class_name>org.postgresql.Driver</database.driver_class_name>
<database.url>jdbc:postgresql://127.0.0.1:5432/bulls_and_cows</database.url>
<database.username>postgres</database.username>
<database.password>postgres</database.password>
<jpa.show_sql>true</jpa.show_sql>
<jpa.generate_ddl>true</jpa.generate_ddl>
<jpa.database>POSTGRESQL</jpa.database>
<jpa.database_platform>org.hibernate.dialect.PostgreSQL95Dialect</jpa.database_platform>
<jpa.hibernate.hbm2ddl.auto>validate</jpa.hibernate.hbm2ddl.auto>
<jpa.hibernate.format_sql>false</jpa.hibernate.format_sql>
<h2.scope>test</h2.scope>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.1</version>
</dependency>
</dependencies>
</properties>
</profile>
<profile>
<id>profile-h2</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<database.driver_class_name>org.h2.Driver</database.driver_class_name>
<database.url>jdbc:h2:mem:h2db;DB_CLOSE_DELAY=-1</database.url>
<database.username>sa</database.username>
<database.password>sa</database.password>
<jpa.show_sql>true</jpa.show_sql>
<jpa.generate_ddl>true</jpa.generate_ddl>
<jpa.database>H2</jpa.database>
<jpa.database_platform>org.hibernate.dialect.H2Dialect</jpa.database_platform>
<jpa.hibernate.hbm2ddl.auto>create-drop</jpa.hibernate.hbm2ddl.auto>
<jpa.hibernate.format_sql>false</jpa.hibernate.format_sql>
<h2.scope>compile</h2.scope>
</properties>
</profile>
</profiles>
This profile overwrites my connection.properties from src/test/resources on src/main/resources.
connection.properties from src/test/resources
database.driver_class_name=org.h2.Driver
database.url=jdbc:h2:mem:h2db;DB_CLOSE_DELAY=-1
database.username=sa
database.password=sa
connection.properties from src/main/resources
database.driver_class_name=${database.driver_class_name}
database.url=${database.url}
database.username=${database.username}
database.password=${database.password}
I wrote testResources tag in build tag of root pom file and in build tag of profile tag such as
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
But instead connection.properties from src/main/resources was always used in test lifecycle of maven.
My old failed build where I used profiles from https://travis-ci.org/WeDism/BullsAndCows/builds/449051809.
My repo with master branch https://github.com/WeDism/BullsAndCows/blob/master/pom.xml.
My repo with with_profiles_h2_postgres branch https://github.com/WeDism/BullsAndCows/blob/with_profiles_h2_postgres/pom.xml
Profile profile-postgres should be main such as activeByDefault = true
For the fix this problem I changed property names such as
<database.driver_class_name> to <database.driver_class_name.pom>.

Include different logback.xml in production build

I use Maven for building and would like to use logback-debugging.xml for developing but package another , logback-info.xml, to the final product.
I came up with the following Maven configuration:
<profile>
<id>development</id>
<activation>
<property>
<name>dev</name>
</property>
</activation>
<build>
<resources>
<resource>
<filtering>true</filtering><!-- if it is neccessary -->
<directory>src/main/logging/develop</directory><!-- from -->
<targetPath>${project.build.outputDirectory}</targetPath><!-- to -->
<includes><!-- what -->
<include>logback.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
In Maven settings file, we can activate one profile per default:
<settings>
[..]
<activeProfiles>
<activeProfile>development</activeProfile>
</activeProfiles>
[..]
</settings>
Another way is to move the default profile configuration to the "normal" pom build section.
To activate the development profile, pass the debug flag via command line, e.g. mvn package -Ddev
Logback searches for configuration files in a specific order (see the docs here). The first place it looks is for a file called logback-test.xml in your classpath. Since you're using maven, include that file in your test/resources directory. That way when you're running any of your tests, the logback-test.xml file is used. For your production code, include logback.xml in your main/resources directory.

Configure active profile in SpringBoot via Maven

I'm trying to set an active profile in Spring Boot application using Maven 3.
In my pom.xml I set default active profile and property spring.profiles.active to development:
<profiles>
<profile>
<id>development</id>
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
but every time I run my application, I receive the following message in logs:
No active profile set, falling back to default profiles: default
and the SpringBoot profile is set to default (reads application.properties instead application-development.properties)
What else should I do to have my SpringBoot active profile set using Maven profile?
Any help highly appreciated.
The Maven profile and the Spring profile are two completely different things. Your pom.xml defines spring.profiles.active variable which is available in the build process, but not at runtime. That is why only the default profile is activated.
How to bind Maven profile with Spring?
You need to pass the build variable to your application so that it is available when it is started.
Define a placeholder in your application.properties:
spring.profiles.active=#spring.profiles.active#
The #spring.profiles.active# variable must match the declared property from the Maven profile.
Enable resource filtering in you pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
When the build is executed, all files in the src/main/resources directory will be processed by Maven and the placeholder in your application.properties will be replaced with the variable you defined in your Maven profile.
For more details you can go to my post where I described this use case.
Or rather easily:
mvn spring-boot:run -Dspring-boot.run.profiles={profile_name}
There are multiple ways to set profiles for your springboot application.
You can add this in your property file:
spring.profiles.active=dev
Programmatic way:
SpringApplication.setAdditionalProfiles("dev");
Tests make it very easy to specify what profiles are active
#ActiveProfiles("dev")
In a Unix environment
export spring_profiles_active=dev
JVM System Parameter
-Dspring.profiles.active=dev
Example: Running a springboot jar file with profile.
java -jar -Dspring.profiles.active=dev application.jar
You can run using the following command. Here I want to run using spring profile local:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=local"
In development, activating a Spring Boot profile when a specific Maven profile is activate is straight. You should use the profiles property of the spring-boot-maven-plugin in the Maven profile such as :
<project>
<...>
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>development</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profiles>
</...>
</project>
You can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Pdevelopment
If you want to be able to map any Spring Boot profiles to a Maven profile with the same profile name, you could define a single Maven profile and enabling that as the presence of a Maven property is detected. This property would be the single thing that you need to specify as you run the mvn command.
The profile would look like :
<profile>
<id>spring-profile-active</id>
<activation>
<property>
<name>my.active.spring.profiles</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>${my.active.spring.profiles}</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
And you can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Dmy.active.spring.profiles=development
or :
mvn spring-boot:run -Dmy.active.spring.profiles=integration
or :
mvn spring-boot:run -Dmy.active.spring.profiles=production
And so for...
This kind of configuration makes sense as in the generic Maven profile you rely on the my.active.spring.profiles property that is passed to perform some tasks or value some things.
For example I use this way to configure a generic Maven profile that packages the application and build a docker image specific to the environment selected.
You should use the Spring Boot Maven Plugin:
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.1.RELEASE</version>
<configuration>
<profiles>
<profile>foo</profile>
<profile>bar</profile>
</profiles>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
I would like to run an automation test in different environments.
So I add this to command maven command:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=productionEnv1"
Here is the link where I found the solution: [1]https://github.com/spring-projects/spring-boot/issues/1095
I wanted to clarify the excellent answer https://stackoverflow.com/a/42391322/13134499 from Daniel Olszewski if you want to use it just for tests.
How to bind Maven profile with Spring for tests?
As you did, define the variable in pom.xml
...
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
Define a placeholder in your application-test.properties in src/test/resources:
spring.profiles.active=#spring.profiles.active#
Enable resource filtering in you pom.xml:
<build>
...
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
<testResources>
</build>
file structure:
/src/main/resources
=>
application.properties:
spring.profiles.active:#spring.profiles.active#'
application-dev.properties
application-prod.properties
IDE-Eclipse:
Right click on the project=>Run As=>Run Configuration=>Arguments=>VM Arguments:-Dspring.profiles.active=dev
CMD:
mvn spring-boot:run -Dspring.profiles.active=dev
mvn clean install -Dspring.profiles.active=dev

Maven: profile-based properties used in plugins section

I would like to mention I am relatively new in Maven configurations.
My situation:
I use Maven 3.0.5 to build J2E application
the application is deployed in four different environments: local, dev, test and prod
I use maven profiles to configure environment-specific configurations
I have defined these configurations in properties files in the file system.
This is the file system for those:
<my-project-root>
---profiles
------local
---------app.properties
------dev
---------app.properties
------test
---------app.properties
I load the corresponding property file with the following logic in my pom.xml:
<profiles>
<profile>
<id>local</id>
<!-- The development profile is active by default -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>local</build.profile.id>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<build.profile.id>test</build.profile.id>
</properties>
</profile>
</profiles>
<build>
<finalName>MyProject</finalName>
<plugins>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>profiles/${build.profile.id}</directory>
</resource>
</resources>
</build>
With this configuration I can use the respective properties for my current profile almost everywhere. Everywhere, but the <plugins> section. I would pretty much like to load e.g, my database url or credentials from such properties files, but if I include them in the app.properties they are not evaluated in the plugins section (e.g. I get value of ${endpoint} as database endpoint).
How do I get the properties loaded from files for the profile accessible in the <plugins> section?
PS: Yes, if I add those properties directly in the pom.xml as properties under <profiles> tag, they are accessible, but I would rather keep my passwords off the pom.
I was able to do what I wanted to do. I used properties-maven-plugin linked from, say this answer.
What I did was the following:
I added the properties-maven-plugin to read the files I needed loaded
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>profiles/${build.profile.id}/app.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
Regretfully, here I was not able to make the plugin read all property files in a directory, but I find this good enough.
I also needed to remove the error the plugin definition above gave for me in Eclipse (Plugin execution not covered by lifecycle configuration). To do thatI followed the instructions from the following post.
With those steps the properties I needed became available for the plugins, that used them.
Note: actually the properties get loaded after the compile maven command, but this is good enough for me, as all my property-dependant goals are to be executed after compile goal in sequence of goal calls in all my cases.

Spring Properties files configuration and maven integration in different env

As being develop a big project using Spring and maven. However there will be different environments to be deployed such as dev, test, staging and production.
The project is having a lot of different properties for different environments.
Are there any elegant way to solve this kind of thing, so I can use this as a template and reuse in other projects.
I guess spring features such as profile, placeholders and etc will be used.
Are there any good tutorial or some blog for me to get a better solution for that?
The Maven concept profile can be your friend :
<profile>
<id>DEV</id>
<build>
<resources>
<resource>
<directory>src/test/dev-resources</directory>
</resource>
<resource>
<directory>src/main/dev-resources</directory>
</resource>
</resources>
</build>
</profile>
<profile>
<id>STAGING</id>
<build>
<resources>
<resource>
<directory>src/test/staging-resources</directory>
</resource>
<resource>
<directory>src/main/staging-resources</directory>
</resource>
</resources>
</build>
</profile>
and run all your Maven build with "-P DEV" for dev propose and "-P STAGING" for staging propose for example .
You can use property configurer. Something like this:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>file:${catalina.home}/conf/your_props.properties</value>
</list>
</property>
</bean>
And you can put your properties (in this case Tomcat servlet container is used) under some config directory in each different environment.
In this case properties are stored under ${catalina.home}/conf where catalina.home refers to Tomcat's installation directory.

Categories

Resources