How to access maven.build.timestamp for resource filtering - maven

I am using maven 3.0.4 and would like to make the build timestamp accessible to my application. For this, I'm putting a placeholder in a .properties file and let maven filter on build. While this is working fine for ${project.version}, ${maven.build.timestamp} is not substituted on filtering.
The property seems to be available on build - I can use it to modify the artifact name:
<finalName>${project.artifactId}-${maven.build.timestamp}</finalName>
So why is it not available for resource filtering? And, more importantly, how do I make it accessible?

I have discovered this article, explaining that due to a bug in maven, the build timestamp does not get propagated to the filtering. The workaround is to wrap the timestamp in another property:
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
</properties>
Filtering then works as expected for
buildTimestamp=${timestamp}

I can confirm as of Maven 3.x {maven.build.timestamp} is "working" now. They work arounded the problem, apparently. No additional properties workaround needed anymore.
However, be careful your "filtering" plugin (maven-resources-plugin) is up to date. It needs to be relatively new, so if mvn help:effective-pom shows an old version (ex: 2.6), bump it to something newer, fixed it for me, 3.x ex:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<properties><timestamp>... workaround is no longer required...
This also cleared up, kind of, why it was working in IntelliJ but not the command line. IntelliJ probably uses their own "modified/internal" maven constants, so it was working there, but not from maven command line.
Also note if you add a filtering resource directory to you pom, you may need to also "re-add" the default directory, it gets lost, ex:
<resource>
<directory>src/main/resources-filtered</directory> <!-- to get "maven.build.timestamp" into resource properties file -->
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory> <!-- apparently have to add this is you have the other... -->
</resource>
NB if you're using spring boot as your parent, you have to use #maven.build.timestamp# instead. Also note if you're using spring boot there's a file META-INF/build-info.properties that is optionally created by the spring-boot-maven-plugin that you can read (spring provides a BuildProperties bean for convenience reading it).

In order to enrich the Stackoverflow content for others, that like me, found this post as a way to solve the "problem" of ${maven.build.timestamp}. This is not a maven bug, but an expected behavior of m2e, as can be seen in this post.
Therefore, I believe that we can not expect the solution to be "corrected", since, from what I understand, the correction involves conceptual issues.
In my case, what I did was use the plugin (buildnumber-maven-plugin) as described in this other post.

Adding Maven properties at the pom project level doesn't take into account correct local Timezone, so timestamp may appear wrong :
<properties><timestamp>${maven.build.timestamp}</timestamp></properties>
Using the build-helper-maven-plugin applies the correct timezone and current daylight saving to the timestamp :
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>timestamp-property</id>
<goals>
<goal>timestamp-property</goal>
</goals>
<configuration>
<name>timestamp</name>
<pattern>yyyy-MM-dd HH:mm:ss</pattern>
<timeZone>Europe/Zurich</timeZone>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
When packaging, Maven will replace any token timestamp in /resources folder, e.g. resources/version.properties :
build.timestamp=${timestamp}
You can then load this properties file in your Application.

Related

Use maven filtering in server.xml without breaking mvn liberty:dev

I would like to use maven filtering, in my src/main/liberty/config/server.xml without breaking the use of liberty:dev from the maven-liberty-plugin. My biggest problem seems to be that the liberty-maven-plugin does not honor filtering.
For example, consider this webApplication element:
<webApplication id="${project.artifactId}" contextRoot="/"
location="${server.config.dir}/apps/${project.artifactId}.war">
</webApplication>
Without any other guidance, this file is copied to target/liberty/wlp/usr/servers/defaultServer/server.xml without any filtering, so the runtime cannot find the WAR file.
Let's say I manually turn on the filtering using maven-resources-plugin:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>01-liberty-config</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/liberty/wlp/usr/servers/defaultServer</outputDirectory>
<resources>
<resource>
<directory>src/main/liberty/config</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Now the filtering works and the file is in the correct location. Unfortunately, I observe that when I run mvn liberty:dev, this gets overwritten by the unfiltered server.xml from src/main/liberty/config/server.xml.
Is it possible to use maven filtering in a server.xml?
BACKGROUND
This is essentially not supported today. The liberty-maven-plugin doesn't let you do this, and the way in which the liberty-maven-plugin manages and controls the Liberty config also doesn't make it easy for you to use standard Maven plugins like 'dependency' or 'resources' plugin either.
Since this issue was raised before I shared a sample approach which you might find useful, though it has the feel of a workaround.
SOLUTION OVERVIEW
Basically, although although we can't substitute into server.xml itself via filters we can substitute into a config snippet that gets included by server.xml, and copy this into place using the resources plugin, rather than liberty-maven-plugin.
SOLUTION DETAIL
Say I wanted to use a "filter"-style Maven variable substitution ${tidal.url} for a URL in Liberty server config.
1. src/main/filtered-config/environment.xml
First define a config snippet, which we are going to apply the filter to.
<server description="environment">
<!-- Expect to come from filter -->
<variable name="tidal.url" value="${tidal.url}"/>
</server>
2. pom.xml
Configure an execution of resources:copy-resources copying the "environment.xml" snippet above to the shared config dir location, target/liberty/wlp/usr/shared/config, with filtering enabled:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>default-cli</id>
<phase>none</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<!-- This location can persist across a server recreate, where the refresh can annoyingly wipe out your earlier copy -->
<outputDirectory>target/liberty/wlp/usr/shared/config</outputDirectory>
<resources>
<resource>
<directory>src/main/filtered-config</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
3. server.xml
In your main server.xml config file, add an <include> of the config snippet you copied into the shared config dir via "copy-resources".
Also shown is how we finally use or "consume" the value applied via the filter, here in this <jndiEntry>, in this sample:
<include location="${shared.config.dir}/environment.xml"/>
<!-- This is how I'm ultimately going to "consume" the filtered value -->
<jndiEntry jndiName="url/tidal-api" value="${tidal.url}" id="TidalJNDI" />
4. Run dev mode, invoking the extra goal first, and activating your filter somehow
E.g.:
mvn resources:copy-resources liberty:dev
As far as activating your filter, maybe you have a filter defined in your build (via build.filters.filter like in my sample repo) or maybe you're just using -Dtidal.url=<value>.
FOLLOW-UP
Besides being complicated a significant limitation of the above is that you only get a single chance to apply the filter. You cannot iterate through different values in a single dev mode "session".
Feel free to give feedback on the issue: https://github.com/OpenLiberty/ci.maven/issues/587
Also I will note we are considering enhancing filter support for general resources and web resources here.
ONE MORE THOUGHT
If all you need is a dynamic way to select, at build time, one set of Liberty config values vs. another you don't necessarily need to use filtering.
You could instead use the support which maps Maven properties to Liberty config.
E.g. for this example you could have one profile which defines
<properties>
<liberty.var.tidal.url>URL1</liberty.var.tidal.url>
</properties>
and another profile defining the same property with a different value.
This would parameterize my sample:
<jndiEntry jndiName="url/tidal-api" value="${tidal.url}" id="TidalJNDI" />
just fine.
The problem though is if you wanted to use the same sets of properties in other contexts with other plugins that did fully support filtering. Then, you want standard Maven filtering.

How to determine what are the attribute necessary to add a plugin in pom.xml

Since last few days a lot of doubts got cleared because of the you all experts. I have one more question, when i see my pom.xml in my project , I see a lot of plugins with quite a few configuration. for e.g
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit-platform</artifactId>
<version>3.0.0-M4</version>
</dependency>
</dependencies>
<configuration>
<forkCount>1</forkCount>
<reuseForks>true</reuseForks>
<argLine>${argLine} -Xmx4g -XX:MaxPermSize=1g</argLine>
<includes>
<include>**/*Test.java</include>
<include>**/*Spec.java</include>
</includes>
</configuration>
</plugin>
My question is how they decided the these forkcount , argLine needed to be used here? plus the dependency also. When i checked the bealdung doc for same plugin the config was very simple. is it necessary to read docs for a perticular plugin before using it. like how people take decisions for the same that what are the tags to be used or what are the mandatory tags. any links will be helpful.
Thanks
I strongly recommend reading the docs of the appropriate plugin which would show like in your example defining the provider (the dependency) https://maven.apache.org/surefire/maven-surefire-plugin/examples/providers.html is usually not needed nor helpful/useful. For the other settings it depends on what kind of tests you are running but from my point of view I would strongly review my tests because needed to set 4 GiB for heapspace sounds weird .... especially for a tests? The others parts depends on the testing framework you are using.. and your use case. I usually start without any configuration for my builds ...only If i really need to change something I do so which is rarely the case. (Convention over configuration)... and read the docs: https://maven.apache.org/surefire/maven-surefire-plugin/plugin-info.html

Spring Boot not loading the active application.properties file

I'm using Spring Boot to activate profiles based on the environment as documented here
For the most part it works. However, I've hit an odd scenario.
I have three application-{profile}.properties files as follows :
application-dev.properties
application-uat.properties
application-release.properties
When I deploy a war file to uat, Spring is picking up a JDBC connection from the release file. The application.properties file contains one line -
spring.profiles.active=uat
If I change the name of the application-release.properties file to application-release.properties.tmp then Spring picks up the connection from application-uat.properties.
Any ideas.
BTW I'm using Spring.Boot 2.2.0-RELEASE
Solved!
Not sure which of the two changes that I made solved the issue but here it is.
When reading the comments in Daniel Olszewski's article, Marcelo Martins says that it is unnecessary to specify resource filtering in pom.xml when using 'spring-boot-starter-parent' which was further confirmed by Daniel. As I am using 'spring-boot-starter-parent', I removed it.
To solve my problem I re-inserted it.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
I upgraded the maven plugin to 2.2.0.RELEASE
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.0.RELEASE</version>
</plugin>

Maven : How to filter one file with own plugin

I'm modifying some maven3 plugin and I just need to filter with file using some properties already defined in the pom starting the whole process.
I haven't found much doc/examples on the topic and all my attempts failed.
First one :
/**
* #component
* #required
* #readonly
*/
private MavenFileFilter mavenFileFilter;
and then in my code :
mavenFileFilter.copyFile(tempFile, resultingFile, true, getProject(), Collections.<String> emptyList(), true, "utf-8", session);
However nothing happens : the replacement isn't done.
Then I saw various examples evolving around
MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution(resources, outputDirectory, getProject(), "utf-8", null, nonFilteredFileExtensions, session);
However I don't get how to put in there the file I want... Resource has no constructor with actual content...
Any help welcome!
Best
EDIT (more context) :
The context is the following : we built a web app deployed at many customers' servers.
On one hand, the folder hierarchy depends from customer to customer.
On the other hand, we have some default logback.xml config file, which needs to be filtered (to use the correct folder hierarchy of the given customer server). This file sits in some common project. We would also like to be able to specialize this logback.xml, when we wish so, on a per customer basis. We've put these files in the source folders of the respective common project/customer project.
As such, the plugin doing the packaging now looks into each artifact, by order of dependencies, and pick up the first logback.xml and put it where needed. It also needs to do the filtering to put the right folders.
It all works apart the last bit...
Does it make sense ? Any better way ?
Thanks again
I would suggest to take a look at this:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/extra-resources</outputDirectory>
<resources>
<resource>
<directory>src/non-packaged-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
...
</project>
Why do you need to implement a plugin which only copies resources within an other life cyclce phase.

How to filter resources when using maven jetty plugin?

I have an XML file (urlrewrite.xml) that needs a property placeholder resolved. I enable Maven filtering to achieve this. This works fine for the assembled WAR file.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
The problem is when trying to run the application in development mode using the maven-jetty-plugin (Maven Jetty Plugin), as maven jetty:run .
The file in question, urlrewrite.xml, is located in the src/main/resources directory, and therefore should (and does) ends up in /WEB-INF/classes (or target/classes for maven jetty:run).
The URLRewriteFilter config specifies the location of the config file as follows:
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>confPath</param-name>
<param-value>/WEB-INF/classes/urlrewrite.xml</param-value>
</init-param>
</filter>
This will work at deployment time. However, Using the jetty maven plugin, URLRewrite will die with a NullPointerException because it uses context.getResourceAsString("/WEB-INF/classes/urlrewrite.xml") in order to load the config file. Jetty returns null for this because when running the application from workspace it resolves /WEB-INF/classes/... to src/main/webapp/WEB-INF/... . The file does not exist there because the WAR has not yet been assembled. It should instead pull the resource from target/classes/urlrewrite.xml.
If that is obscure to you, then you probably won't be able to answer this question because I suspect you will need to be a Jetty guru to figure out a workaround (hint: that's a challenge!).
Does anyone know a way around this? I have also tried the following workarounds to know avail:
Put urlrewrite.xml under a new directory, src/main/webResources and add it to the maven war plugin <webReources> and enable filtering. That will copy it's contents in the appropriate location when the WAR is packaged, but will not make it available for jetty:run
Some other hacks I can't even remember ... (will update if I do)
In summary, maven-jetty-plugin needs the file to be under src/main/resources/webapp/insert path and filename in order to be available for the maven jetty:run command ...
Thanks for you help ...
Sincerely,
Lloyd Force
Answered my own question.
Upgrade maven-jetty-plugin to at least 6.1.12
See this wiki page on 'Configuring Multiple WebApp Source Directory' (available since jetty-6.1.12.rc2 and jetty-7.0.0pre3)
Add some magic to pom.xml:
First, add a new directory (src/main/webResources) for your filtered web resources and add a <resource> element:
<resource>
<directory>src/main/webResources</directory>
<filtering>true</filtering>
<targetPath>../jettyFilteredResources</targetPath>
</resource>
That will copy the files to target/jettyFilteredResources (we will reference this later). This directory will NOT get copied to your packaged WAR file, it is for jetty only!
Add the following element to your maven-war-plugin <configuration> element:
<webResources>
<resource>
<directory>src/main/webResources</directory>
<filtering>true</filtering>
</resource>
</webResources>
That will ensure everything is packaged up for your real WAR file.
Finally, tell jetty to use the resources your copied especially for it, by added the following snippet to your <baseResource> element:
<baseResource implementation="org.mortbay.resource.ResourceCollection">
<resourcesAsCSV>src/main/webapp,target/jettyFilteredResources</resourcesAsCSV>
</baseResource>
Now everything will worketh! (Well, technically I haven't tested the production WAR yet, but ... blah ... it should work too).
If anyone has a better answer, I will accept it provided the answer is provided in a reasonable amount of time (say 1 day).
I think the answer in this other question is better:
Running resource filters when using jetty:run
Basically, instead of running 'mvn jetty:run' you have to use 'mvn jetty:run-exploded'.
The only drawback is that it needs to build the WAR file, which might be expensive in some cases. If that's not an issue for you, then I guess it's better.
add this to pom.xml:
<resources>
<resource>
<directory>src/main/webapp/WEB-INF</directory>
<filtering>true</filtering>
<targetPath>../jettyFilteredResources</targetPath>
</resource>
</resources>
and this is how embedded Jetty server should look like:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.3.v20140225</version>
<configuration>
<webAppConfig>
<descriptor>target/jettyFilteredResources/web.xml</descriptor>
</webAppConfig>
<scanIntervalSeconds>3</scanIntervalSeconds>
</configuration>
</plugin>
woila! thanks #les2 for inspiration ;-)
I found another way.
build the project and add the target folder as extra classpath.
<webAppConfig>
....
<extraClasspath>${basedir}/target/mywebapp</extraClasspath>
....
</webAppConfig>

Resources