I can't get maven to use properties defined in ~/.m2/settings.xml? - maven

I am using ~/.m2/settings.xml to store a number of property names used throughout the pom.xml files in my project. If I make the XML invalid (by adding another < for example), maven immediately generates an error, saying that it cannot parse that file. If I leave the XML valid, settings in my appBeans.xml file do not pick of references to properties defined in settings.xml.
Has anyone experienced this problem? I am sort of at my wits end here.

Reflecting properties from Maven configurations works by resources filtering.
Make sure your settings.xml, project pom and the target xml file contain correct configurations and reside in correct places.
If I understood correctly, you want to store a property name and value in the settings.xml so the props can be used in your project files. I'll provide a working example:
Define a default profile and properties in settings.xml:
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<someProp>Value</someProp>
</properties>
</profile>
</profiles>
Define resource folder's filtering=true in pom.xml:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Define the property in the xml file (that resides in the src/main/resources folder):
...
<element>${someProp}</element>
...
After this you should see the filtered result e.g. in target/classes/appBeans.xml.
Bear in mind that if you're using Eclipse & m2eclipse or similar plugin, it probably won't start using the updated settings.xml without restarting Eclipse and it's automatic build will sometimes overwrite your files in the target folder. I'm talking from experience here :)

Maven properties do not get reflected in miscellaneous XML files.
If you add one of these properties to the <properties/> element of the specific pom that runs the specific plugin that reads allBeans.xml, does that work? I believe that it will not, and your problem will turn out to be adding to the <configuration/> for the plugin to pass the maven properties to it.
If you edit your question to show the plugin that processes appBeans.xml I can make this more specific.

Related

Could i use maven profile to swith between different value application.properties

I have application-prod.yml application-dev.yml, and application.properties which containing just one line code like below
spring.profiles.active=dev
for maven production build, it should use spring.profiles.active=prod , then it will build with application-prod.yml, for development build, it should use spring.profiles.active=dev, then maven
will use application-dev.yml to build
could I use pom.xml's different profile to do switch for this value switch in applicaiton.properties?
You can use a Maven property for this, reference it in your yml file (with ${...}) and filter the resource (i.e. the yml file) with the maven resources plugin.
It seems that what you're after is "externalized configuration". According to the excellent 12factor guidelines, it is best not to keep such config inside your code-repository.
Refer to the relevant section in the Spring Boot manual to see which options you have (and there are many). What it comes down to is that you provide your application.yml/properties file on the filesystem and your application will read it from there, rather than from the classpath.
Also, note that spring-profiles are not meant to be used to distinguish between development environments, but rather to put the application in different functional modes (e.g. to enable or disable specific features).
If you want the content of your properties file changed at build time, then you can use Maven filtering. Maven filtering allows to replace a placeholder in your properties (or yaml) file by values from Maven properties.
Assuming you have a property in your POM called targetEnv, which might have either the value dev or prod (depending on the active Maven profile), then you can refer it in your properties file (or yaml file) by using the following syntax :
spring.profiles.active=#targetEnv#
However, if you want to follow Spring Boot recommandations, it is better to enable and disable the Spring profiles by the means of environment variables in your target environment. For instance, you can use an environment variable spring.profiles.active with the desired value and it will override the value in your properties file.
You need to define a custom property in each of your Maven profiles and set their values to match with suffixes of corresponding properties files that you want to load with a particular profile.
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>release</id>
<properties>
<activatedProperties>release</activatedProperties>
</properties>
</profile>
Next, in the build section of the same file, configure filtering for the Resources Plugin. That will allow you to insert properties defined in the previous step into any file in the resources directory, which is the subsequent step.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
Finally, add the following line to the application.properties.
spring.profiles.active=#activatedProperties#
For more details, please see spring boot properties per maven profile
For official guide to load from external configLoad from external Config

Is it possible to use a maven property to activate a profile based upon a file?

I would like to download the JACOB dlls when they're not in my local repository.
As a consequence, I have those two profiles
<profile>
<id>use-jacob-dll</id>
<activation>
<file>
<exists>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</exists>
</file>
</activation>
<dependencies>
<dependency>
<groupId>${jacob.groupId}</groupId>
<artifactId>jacob</artifactId>
<type>dll</type>
<classifier>x64</classifier>
<version>${jacob.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>download-jacob-dll</id>
<activation>
<file>
<missing>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
But, even when download-jacob-dll has accomplished its goal, a call to mvn help:active-profiles indicates the following
The following profiles are active:
- tests-for-eclipse (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
- download-jacob-dll (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
I suspect it is due to the fact that I use the ${settings.localRepository} in my activation property.
Question: Is it the cause of the failure? And if so, how can I activate my profile only when dependency is missing ?
Is it possible to use a maven property to activate a profile based upon a file?
No, as stated by the Maven documentation on profiles
Supported variables are system properties like ${user.home} and environment variables like ${env.HOME}. Please note that properties and values defined in the POM itself are not available for interpolation here, e.g. the above example activator cannot use ${project.build.directory} but needs to hard-code the path target.
However, from the POM documentation we also get that
a given filename may activate the profile by the existence of a file, or if it is missing. NOTE: interpolation for this element is limited to ${basedir}, System properties and request properties.
Hence, indeed no Maven properties except ${basedir} are allowed.
And if so, how can I activate my profile only when dependency is missing?
By hardcoded path to the dependency or concerned file would be a solution, even though not portable like the solution you meant.
Alternatively you could use a request property as mentioned by the documentation above, thus need to configure the activation with a property which then must be passed from the command line (more portable but more fragile as well):
<activation>
<file>
<missing>${path}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
Then invoke maven as following:
mvn clean install -Dpath=path_to_local_rep
The solution above could be reasonable in some contexts like Jenkins jobs.

Using the properties tag within maven profiles

I am in reference to "Maven: The Complete Reference" and especially the section regarding profiles which documents the use of a <properties... tag within the <profile... tag here: see here
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>environment.type</name>
<value>dev</value>
</property>
</activation>
<properties>
<database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName>
<database.url>
jdbc:mysql://localhost:3306/app_dev
</database.url>
<database.user>development_user</database.user>
<database.password>development_password</database.password>
</properties>
</profile>
What I am not sure about is what happens when the mvn install -Denvironment.type=dev command is run:
Will this create a .properties file?
If not how and where will tomcat (for instance) read the individual properties when the app is tested in dev?
Will this create a .properties file?
No, it won't. This would set the properties used by maven. This is, with mvn install -Denvironment.type=development maven would use the value 'development_user' for the variable 'database.user' (that you can use as ${database.user} in poms and filtered resources).
If not how and where will tomcat (for instance) read the individual properties when the app is tested in dev?
The thing is to tell maven to filter (and modify) the resources that you want to customize depending on the profile (properties.files).
So, first you have to say maven to filter the resources:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Then modify your properties files to use maven variables. For example, your db properties file would look like this:
database.driverClassName=${database.driverClassName}
database.url=${database.url}
#...

read Maven variable from properties file using profile

I want to read a maven variable for configure a build plugin from a properties file. It's not needed in and further project files e.g. context files.
1) made a profile (it works, can use mvn ... -P private)
<profile>
<id>private</id>
<properties>
<env>private</env>
</properties>
</profile>
2) created the filter file with this content (it works)
foo.path=/home/foo/path
3) try to configure the plugin (does not work)
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>foo-plugin</artifactId>
<version>${foo-plugin.version}</version>
<configuration>
<!--<fooPath>home/foo/path></fooPath> that works -->
<fooPath>${foo.path}</fooPath> <!--works not -->
</configuration>
...
</build>
Thx a lot
The name of your property is 'env' but you don't use env anywhere in your configuration.
When Maven docs mention "filter files" they usually mean a file used when processing resources (i.e. copying resources from /src/main/resources to target/classes). As far as I know the properties in those files aren't used for plugin configuration out-of-the-box. I have used the Codehaus properties-maven-plugin:read-project-properties goal do do what you are attempting. Make sure you bind the goal to the lifecycle before any plugins that need the properties for config.
Also, see this answer; you may load properties used to configure other plugins, but not to configure core Maven project elements.

How does IntelliJ's Maven filtering support work?

I have noticed when you configure a Maven project to use property filtering the property filtering seems to also work during a non-maven IntelliJ "make". This means the IntelliJ run configurations for Jetty/Tomcat/GWT/Glassfish will still honour your maven resource filtering.
So if I add this to my pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/persistence.xml</include>
</includes>
</resource> ....
It should filter any properties in my properties and peristence.xml files before any intellij run configurations start. This is very usefull for swapping in JDBC references or filesystem parameters.
The only problem I am having is that IntelliJ only seems to honour filtering in src/main/resources even if I change pom.xml to have a second entry for other directories (ie:src/integrationtest/resources).
This all seems to be "automagical". So how does it work and where (if anywhere) can I configure it?
IntelliJ IDEA's Make features are capable of filtering Maven resources. However, IntelliJ IDEA yet does not support filtering web resources.
source: http://www.jetbrains.com/idea/webhelp/maven.html#compile
No further details about this support in whole intellij webhelp though, so I guess it should work just like maven's process-resources phase does.
The problems you are having can be caused by the fact that directory src/integrationtest/resources doesn't follow maven conventions.
Maybe it will work if you:
make it src/test/resources/integrationtest/
or
configure maven to respect src/integrationtest as test sources (but if integrationtest isn't well-known convention it will be violation of maven's COC rule)
or
make it another maven (sub)module, if you want to emphasize isolation of integrationtest
As for filtering directories different that src/main/resources: filtering src/main/webapp/META-INF worked out-of-a-box for me.
(Maven 3.0.4, Intellij 12.1.4)
Good news, looks like the issue will be fixed in 13.1
http://youtrack.jetbrains.com/issue/IDEA-25934
EDIT: Sorry if not clear enough, the bug case is just marked as "fixed" with no further explanation...
But I tested in 13.1 EAP version (build 134.1445) and while previously IntelliJ would overwrite the resources, it now preserves the web resources filtered by Maven.
Intellij (I'm using 14.1) does allow you to define custom Ant tasks as pre-/post-processing during artifact build.
Go to Project Structure -> Artifacts -> {select artifact} -> {Pre-processing|Post-processing} tabs.
So, for example, I can use the following simple task to simulate resource filtering in cases where it doesn't work out of the box:
<target name="filter" depends="clean">
<copy todir="${maven.build.dir}/${maven.build.finalName}">
<fileset dir="${maven.build.resourceDir.0}"/>
<filterset begintoken="${" endtoken="}">
<filter token="project.version" value="${project.version}"/>
</filterset>
</copy>
</target>
Don't forget to define a default profile
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
...
</properties>
</profile>
</profiles>

Resources