Refer to Maven project paths from Java - java

I need to programmatically gather some paths inside a Maven project, in particular to refer to the project artifact.
Using
URL MyClass.class.getClassLoader().getResource(String name)
works for a path relative to the target/classes folder of the project, but since the artifact sits in the target folder it is not possible to reference it. A path like
System.getProperty("user.dir") + "/target"
does not convince me at all at least for the fact that the target folder name, while standard, is not safely portable.
Is there a Maven-aware library solution that exploits a relative path?

MavenProperties can be written to a manifest file using the maven archiver which is used by the maven war plugin or the maven jar plugin.
If you have a web app, then you can pass some information to the web.xml file, too.
This is an example of one of my projects:
from pom.xml:
------------------------------------------------
<properties>
<maven.build.timestamp.format>dd.MM.yyyy' 'HH:mm:ss</maven.build.timestamp.format>
<build-version>${env.SVN_REVISION}</build-version>
<build-date>${maven.build.timestamp}</build-date>
</properties>
.
.
.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<webResources>
<webResource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<includes>
<include>web.xml</include>
</includes>
<targetPath>WEB-INF</targetPath>
<filtering>true</filtering>
</webResource>
</webResources>
from web.xml:
------------------------------------------------
<context-param>
<param-name>BUILD_VERSION</param-name>
<param-value>${build-version}</param-value>
</context-param>
<context-param>
<param-name>BUILD_DATE</param-name>
<param-value>${build-date}</param-value>
</context-param>

Related

Non-java resources disappear from class package after maven packaging

I'm trying to create a Spring project structure where I have my HTML templates stored in the same src/main/java package (in Tapestry-like way), so the structure basically looks like this:
src/main/java
-org
-example
-views
-pageOne
PageOneController.java
Template.html
-pageTwo
PageTwoController.java
Template.html
However after packaging a WAR while using Maven I get a structure like this:
WEB-INF/classes
-org
-example
-views
-pageOne
PageOneController.class
-pageTwo
PageTwoController.class
So the .html files are ignored and obviously nothing works.
I tried to configure maven-resources-plugin to copy those resources like this:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<filtering>false</filtering>
<includes>
<include>*/**.html</include>
</includes>
<excludes>
<exclude>*/**.java</exclude>
</excludes>
</resource>
</resources>
</build>
but to no avail.
How do I configure my project to copy non-java files from src/main/java into the final output?
It turns out that the problem was with maven modules. I have declared resources plugin in the main pom.xml instead of the module's pom.xml which lead to the configuration issues.

Compatibility problem between maven and maven-resources-plugin

I'm using maven-resources-plugin to copy a file from resources dir to output dir and inject a variable;
there is the pom of the project:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4</version>
<configuration>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</plugin>
the resource file is something like this:
operation=${var}
and in he pom there is:
<properties>
<operation>true</operation>
</properties>
When I build the project (mvn -U clean package ) locally everything works fine: the file .properties is correctly inside the jar and it contains "operation=true".
The problem appears when I deploy the jar to my artifactory. If I download and open the jar from artifactory I can still find the .properties file, but in this case it contains: "operation=${var}" (the plugin doesn't inject the value of the variable). The command for the build inside the .yml file is the same that I run locally (mvn -U clena package). Any suggestions? The only difference that I can see is that on my computer I have maven 3.6.1 and on the server where I build the project for artifactory there is maven 3.3.3.

maven-ear-plugin project property lookup fails

I have created simple ear project with filters. I want to use different settings for each environment, those settings should be passed to generated application.xml file in the form of env-entries. The generation of ear package is done with maven-ear-plugin as shown below:
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<configuration>
<generateApplicationXml>true</generateApplicationXml>
<version>6</version>
<envEntries>
<env-entry>
<env-entry-name>customProperty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>${custom.property}</env-entry-value>
</env-entry>
</envEntries>
<applicationName>${custom.property}</applicationName>
</configuration>
</plugin>
To do that I had to use another plugin properties-maven-plugin. It successfully reads properties from file and sets them as maven project properties, so I can insert them in pom.xml file using ${}. It works for most of the pom.xml elements (i.e. <applicationName>, unfortunately it is not successfully looked up when I place it inside env-entry element, where I need it. Below is generated application.xml.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
<application-name>default property</application-name>
<display-name>test</display-name>
<env-entry>
<env-entry-name>customProperty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>${custom.property}</env-entry-value>
</env-entry>
</application>
It's probably a bug which should be issued at Maven Ear Plugin, but I don't have an account there. I'm also attaching archived maven project, if somebody would like to check that himself: test.zip.
Edit
I've managed to overcome this problem using maven-resource-plugin and filter application.xml file after it's created as user #skegg99 proposed. Since I cannot replace this file I had to copy it to META-INF directory. I does not look pretty, I know, but it solves the case for now. Here is additional markup for maven-resource-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${basedir}/target/${project.artifactId}-${project.version}/META-INF</outputDirectory>
<filters>
<filter>src/main/filters/${env}.properties</filter>
</filters>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
and also here:
<resources>
<resource>
<directory>${basedir}/target</directory>
<filtering>true</filtering>
<includes>
<include>application.xml</include>
</includes>
</resource>
</resources>
Whole project configuration can be downloaded from here.
With the current setup you have this may well be impossible.
I just took a brief look into the code where it states that the env entries are load through the PlexusConfiguration.
Without diving too deep into that code as well, I can't see that this part handles the entries any more special than "read XML, put into List".

Conditional inclusion of files in maven

I have a JEE6 web application project.The project structure is according to maven convention.
Now I have introduced additional web.xml files for this project.
So they are now stored in WEB-INF as below:
WEB-INF/
|__ A/web.xml
|__ B/web.xml
What is the maven way to build a war to include proper xml depending upon the property.
I know the how to add custom properties in maven.But I cannot find how to configure the maven plugin such that during the war file building it chooses the appropriate file.
Any hints/suggestions/maven best practices in such cases are most welcome.
Thanks!!
maven war plugin could be configured to add and filter some external resources. See http://maven.apache.org/plugins/maven-war-plugin/examples/adding-filtering-webresources.html.
So I would make 2 maven profiles with 2 war plugin configuration like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>src/main/webapp/WEB-INF/__A</directory>
<includes>
<include>web.xml</include>
</includes>
<targetPath>WEB-INF</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
<!-- repeat for your second profile -->
BUT I think a better solution (and if your project permits it) would be to keep only one web.xml file with some filtered properties inside. In this case, you should just configure your war plugin to enable some filtering like this :
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>

Resource files not found from JUnit test cases

Summary
My JUnit tests are not finding the files they require during execution.
I'm using Maven for dependency management and compilation.
Details
All files required by the test cases are located in: src/test/resources.
For example, src/test/resources/resourceFile.txt.
To access a resource I use the following code:
URL url = getClass().getResource("/resourceFile.txt").getFile();
File file = new File(url);
But then file.exists() returns false. And the error I get is:
Tests in error:
myJUnitTestCase(tests.MyJUnitTestClass): /home/me/workspace/Project%20Name/target/test-classes/resourceFile.txt (No such file or directory)
Note, the following gives the same error (notice the removed / prefix):
URL url = getClass().getClassLoader().getResource("resourceFile.txt").getFile();
File file = new File(url);
It seems as though the files from src/test/resources are not getting copied into target/test-classes.
Any ideas?
The following questions did not help
Why Can't I access src/test/resources in Junit test run with Maven?
Loading Properties File In JUnit #BeforeClass
How to deal with the test data in Junit?
Software Versions
Ubuntu 12.04
Apache Maven 2.2.1
Java 1.7.0
Eclipse (Java EE IDE for Web Developers) Indigo Service Release 2
(truncated) Maven POM
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.groupId</groupId>
<artifactId>artifactId</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>name</name>
<build>
<finalName>name</finalName>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
My mistake, the resource files WERE actually copied to target/test-classes. The problem seemed to be due to spaces in my project name, e.g. Project%20Name.
I'm now loading the file as follows and it works:
org.apache.commons.io.FileUtils.toFile(myClass().getResource("resourceFile.txt")‌​);
Or, (taken from Java: how to get a File from an escaped URL?) this may be better (no dependency on Apache Commons):
myClass().getResource("resourceFile.txt")‌​.toURI();
You know that Maven is based on the Convention over Configuration pardigm? so you shouldn't configure things which are the defaults.
All that stuff represents the default in Maven. So best practice is don't define it it's already done.
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
This is actually redundant except in cases where you want to override the defaults. All of these settings are implied defaults.
You can verify that by checking your effective POM using this command
mvn help:effective-pom
<finalName>name</finalName>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
For example, if i want to point to a different test resource path or resource path you should use this otherwise you don't.
<resources>
<resource>
<directory>/home/josh/desktop/app_resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>/home/josh/desktop/test_resources</directory>
</testResource>
</testResources>
You may have defined:
<packaging>pom</packaging>
If you did this, the resources won't be present in the target directory when you will launch your tests. And mvn package won't create it either.
At the contrary, if you define:
<packaging>jar</packaging>
Or nothing as the default value is jar. As Maven is based on Convention over Configuration. You will end up with:
src/main/resources => target/classes
src/test/resources => target/test-classes
Main classes should be under src/main/java
and
test classes should be under src/test/java
If all in the correct places and still main classes are not accessible then
Right click project => Maven => Update Project
Hope so this will resolve the issue
The test Resource files(src/test/resources) are loaded to target/test-classes sub folder. So we can use the below code to load the test resource files.
String resource = "sample.txt";
File file = new File(getClass().getClassLoader().getResource(resource).getFile());
System.out.println(file.getAbsolutePath());
Note : Here the sample.txt file should be placed under src/test/resources folder.
For more details refer options_to_load_test_resources
Make 'maven.test.skip' as false in pom file, while building project test reource will come under test-classes.
<maven.test.skip>false</maven.test.skip>

Categories