I am working on a java web application, managed by maven2. From time to time, we did some changes, and want to do new releases, of course with new version number. In the hom
I use this plugin,
http://code.google.com/p/maven-substitute-plugin/
You can do something like this in Java,
public final static String projectVersion = "@PROJECT_VERSION@";
and it's trivial to pass this value to JSP.
I would hand the .jsp the value of
String version = getClass().getPackage().getImplementationVersion();
that would look like 1.0.0-SNAPSHOT
for instance.
If you are just getting nulls, you may need to add the classpath to the Manifest of the war
with
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
for the classloader to pick it up.
You can use project filtering to process the JSP as it is copied to the target location. If the JSP is specified with ${project.version}
, and the containing folder is specified as a filter location the value should be substituted into the JSP as it is packaged.
For example, adding this to your POM enables filtering for src/main/resources:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Update: for war packaging, you may need to configure the war plugin to do its filtering. See the Filtering
section of the war-plugin's documentation for more details and examples.
Essentially the process is the same, but it is defined below the war plugin, so you'd have something like this:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0</version>
<configuration>
<webResources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
There are many ways of passing the values (as discussed in these comments). Another approach (which has its own pros and cons) is to add the parameter(s) to the manifest from your POM file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestEntries>
<Build-Version>${project.version}</Build-Version>
<Build-Date>${buildDateTime}</Build-Date>
<Build-Number>${buildNumber}</Build-Number>
<Build-Revision>${buildRevision}</Build-Revision>
</manifestEntries>
</archive>
</configuration>
</plugin>
and then open and read the manifest to set a singleton bean during configuration or directly import them into the JSP with:
<%
String buildVersion;
String buildDate;
String buildRevision;
String buildNumber;
Attributes attributes;
String version = "";
InputStream in = null;
// Get manifest attributes
try {
Manifest manifest;
in = pageContext.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
manifest = new Manifest(in);
attributes = manifest.getMainAttributes();
} catch (Exception ex) {
attributes = new Attributes();
attributes.put(new Attributes.Name("Build-Version"), "None (Inplace Deployment)");
} finally {
if (in != null) {
in.close();
}
}
buildVersion = attributes.getValue("Build-Version");
buildDate = attributes.getValue("Build-Date");
buildRevision = attributes.getValue("Build-Revision");
buildNumber = attributes.getValue("Build-Number");
%>
One advantage is that this information is also present in the manifest as easy to locate documentation. One disadvantage is the need to open and read the manifest file.
I wanted to do this very same thing but I was not satisfied with any of the existing solutions, including using the Maven filtering approach, which is ok, but I am trying to move away from modifying existing code files during the build process so I ruled that approach out, although it is a reasonable approach.
The way I get my Maven project version into my JSP file is based on a similar approach to the one from here except that I don't create a Version.java file, instead I just have Maven write the version out to a properties file, such as "version.properties" like this:
version.properties:
app.version = 0.1
and have Maven put it on the classpath, for instance, in src/main/resources like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<goals>
<goal>run</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<!-- Idea from link: http://stackoverflow.com/questions/2469922/generate-a-version-java-file-in-maven -->
<target>
<property name="resources.dir" value="${project.build.sourceDirectory}/../resources" />
<property name="version.filename" value="version.properties" />
<property name="buildtime" value="${maven.build.timestamp}" />
<echo message="Writing project version string to ${resources.dir}/${version.filename} ..." />
<echo file="${resources.dir}/${version.filename}" message="app.version = ${project.version}${line.separator}" />
</target>
</configuration>
</execution>
</executions>
</plugin>
Also, if you are using Spring Framework 3.x+ then you can add the following configuration to load properties in version.properties if it exists, otherwise just show "v0.0" or whatever:
@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class WebHomeConfig extends WebMvcConfigurerAdapter implements
ApplicationContextAware {
private ApplicationContext _appContext;
/*
* (non-Javadoc)
*
* @see
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
_appContext = appContext;
}
@Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.getAttributesMap().put("appVersion", appVersion);
return resolver;
}
/**
* Since we don't have any controller logic, simpler to just define
* controller for page using View Controller. Note: had to extend
* WebMvcConfigurerAdapter to get this functionality
*
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
/**
* The application version.
*/
@Value("${app.version:0.0}")
protected String appVersion;
@Bean
public static PropertySourcesPlaceholderConfigurer configurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreResourceNotFound(true);
configurer.setLocations(new Resource[] {
new ClassPathResource("version.properties")});
return configurer;
}
}
And finally, in your /WEB-INF/views/home.jsp you can have something like:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Service Status</title>
</head>
<body>
<h1>Service API</h1>
<p>The service is up and running! (v${appVersion})</p>
</body>
</html>
And this would of course render as:
The service is up and running! (v0.1)
NOTE: If you don't use the JavaConfig classes to configure Spring Framework then you can do the same thing with Spring XML configuration.