Hi all!!
Sorry if this is a dumb question, but I'm new to Maven and have reached an impasse!
I have a project which uses MyTest.properties, MoreMyTest.properties.
I use the Maven Shade plugin to build this project into a .jar file, which is working fine! Unfortunately, the shade plugin is packaging MyTest.properties inside my jar file.
Then, I get this error when I try to execute the jar.
java.io.FileNotFoundException: Unable to locate: properties/MyTest.properties at file:\C:\Dev\test.jar!\properties\MyTest.properties
at ...
I'm wanting to access my properties both inside my IDE, and by running the jar from the command line when I deploy. I was thinking of having my properties files in a relative folder ../lib/ above the location of my jar file.
Inside my program I want to access the properties like so:
File testProperties = new File(
ClassLoader.getSystemResource("properties/MyTest.properties").getFile()
);
I tried adding this to my POM.xml
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>*.properties</resource>
<file>../*properties</file>
</transformer>
(Sorry the formatting got messed on the above code snippet!)
But, it's not working. I'd really appreciate any help in this. I've not posted all code as the code is really big, but I hope you can get an idea of what I'm trying to achieve.
Many thanks,
Paul
Ok, I have a solution. Always the way, just after posting! But thanks for your reply.
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>../lib</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Related
I use the org.apache.maven.plugins maven-assembly-plugin version 2.2-beta-5 to build a jar-with-dependencies. One of the jars I include contains a persistence.xml file. The project that I build also has a persistence.xml file. The build finishes well.
The problem however is that most of the times the wrong persistence.xml file ends up in the jar-with-dependencies. If I, without changing anything, rebuild (and sometimes a few more times) then the correct persistence.xml is present.
I searched for a solution but I could not find a working example. How can I define in my pom.xml that I want my project's persistence.xml file in the jar-with-dependencies and not the one from the included jar?
My MaVeN version is Apache Maven 3.6.3 and all builds are done with mvn clean package.
Use maven-shade-plugin instead of mavenassembly-plugin to exclude the persistence.xml file from your dependencies
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>my:other:jar</artifact>
<excludes>
<exclude>persistence.xml</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
More info on this approach in the Apache Maven Shade Plugin documentation
Cannot comment about time taken to build the executable without looking into your project.
By default Maven copies files from your ${project.basedir}/src/main/resources location to the executable jar file. So If persistence.xml is not being included in fat jar then check your folder structure and check the location of your xml file.
One of the many modules I'm working on uses "generated-sources" for a couple auto-generated Java classes that the rest of the code depends on. Unfortunately, every single time I do a git pull it gets reset and I have to do mark the folder as "Generated Sources Root" again.
It's not a deal breaker, but it's really annoying. Isn't there a way to automate this? I don't know, some setting in IntelliJ or perhaps even directly in the pom.xml?
You can give a try to build-helper-maven-plugin and add more source directories to your project explicitly:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/...</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Also there is a little trick - actual source generation must happens before this goal execution.
In our project IDEA works pretty well with this approach.
Try adding generated-sources folder to git ignore file. Git ignore file if not already exists can be added in intelli idea like:
Then add generated-sources folder relative path like generated-sources/in git ignore file & commit .gitignore file. From next time any changes in that folder will not be overwritten or will be committed to server.
I have a multimodule maven application that has the following structure:
main-project
->submodule1
->src->main
->java
->MainClass.java
->resource
->php
index11.php
file12.php
file13.php
->submodule2
->src->main
->java
MainClass.java
->resource
->php
index21.php
file22.php
file23.php
->submodule3
->src->main
->java
MainClass.java
->resource
->php
index31.php
file32.php
file33.php
->web-app
->src->main
->webapp
Java classes from submodules should access the php files in their resource directories and execute it using Quercus Resin. However, when the project is packed in war, submodules are packed into jar file that are stored in web-app/WEB-INF/lib, which makes it impossible to execute php files. As workaround for this problem, I found solution to copy all php files from the submodules into the web-app, so when it's extracted in Tomcat, it's not inside jar file and could be executed. For that purpose, I'm using maven-remote-resources-plugin, and all php files are stored to web-app/src/main/webapp/php.
The problem I have now is how to properly provide path to these php files from java classes inside submodules.These java classes are inside jar files when application is deployed to Tomcat, but during development I'm using embedded Jetty server, so I need solution that would work in both cases.
If I use class loader to get resource,e.g. getClass().getClassLoader().getResource("/php/index11.php").getPath() it returns absolute path to the submodule1.jar file.
Any idea how to solve this issue?
I managed to solve this problem, so I will post solution here if it might help someone else.
In each submodule I have a maven-remote-resources-plugin bundle to collect all resources I need
<build>
<plugins>
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<goals>
<goal>bundle</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*.php</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Then, in web-app submodule I'm using maven-remote-resources-plugin process to copy these php files to resource directories called WEB-INF/php/submodule-name
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.5</version>
<configuration>
<resourceBundles>
<resourceBundle>org.au.morph.offline:morph-sample:${project.version}</resourceBundle>
<resourceBundle>org.au.morph.offline:morph-project:${project.version}</resourceBundle>
</resourceBundles>
<outputDirectory>src/main/webapp/WEB-INF</outputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
Finally, I created a utility method that resolves the correct path to this directory both when I run application from IDE or in the Tomcat:
public static String getWebContentPath(String contextPath) throws UnsupportedEncodingException {
String path = PathUtils.class.getClassLoader().getResource("").getPath();
String fullPath = URLDecoder.decode(path, "UTF-8");
if(fullPath.contains("/WEB-INF/classes")){
String pathArr[] = fullPath.split("/classes/");
fullPath=pathArr[0];
}
String reponsePath = "";
reponsePath = new File(fullPath).getPath() + File.separatorChar + "php"+File.separatorChar+contextPath;
return reponsePath;
}
I am building an executable jar file with maven, meaning that you run it with "java -jar file.jar".
I want to rely on user defined properties (just a file containing keys/values), during developpement phase I was putting my "user.properties" file in maven /src/main/resources/ folder.
My property file is loaded with:
final Properties p = new Properties();
final InputStream resource = IOParametres.class.getResourceAsStream("/user.properties");
p.load(resource);
Now, I want to keep that file outside of the JAR and have something like this :
- execution_folder
|_ file.jar
|_ config
|_ user.properties
I tried many things with maven plugins like maven-jar-plugin, maven-surefire-plugin and maven-resources-plugin but I can't get it working...
Thanks in advance for your help!
I found what I needed using only maven configuration.
First I add config folder to the classpath:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestEntries>
<Class-Path>config/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
I load resources the same way as before:
final InputStream resource = IOParametres.class.getResourceAsStream("/user.properties");
p.load(resource);
And if you want to keep your example resource files in your repo and remove them from your build:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>user.properties</exclude>
<exclude>conf/hibernate.cfg.xml</exclude>
</excludes>
</resource>
</resources>
</build>
Next to the jar file, I add a config folder holding all the resource files I need.
The result is:
user.properties can be loaded using getResourceAsStream
other libraries relying on specific resources (I won't argue, but I find it... not that good) can load their resources without any issue.
Thanks for the help, and I hope it may help somebody someday!
As I mentioned in the comment - it looks like you want to use user.properties file simply as a text file that lies besides your jar. If that's the case, than using it is rather simple - directory containing your jar file is the current directory when checked during runtime. That means that all you need is:
properties.load(new FileInputStream("config/user.properties"));
without trying to put in on the project classpath.
And if anything else is there to be done, it would just by copying your properties from resources directory to target to avoid the hussle of doing it by hand. That can be achieved by maven-antrun-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<mkdir dir="${project.build.directory}" />
<copy file="${basedir}/src/main/resources/user.properties" tofile="${project.build.directory}/config/user.properties" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
Scenario is such: I have a webapp that I'd like to run dynamically with the tomcat-maven-plugin's tomcat:run goal. The wrinkle is that I have numerous classpath resources that need to differ between the packaged artifact and the one run off a local workstation.
Failed Attempts:
1.) My first attempt was to use the builder-helper-maven-plugin, but it won't work because the target configuration files will (inconsistently!) work their way into the packaged WAR archive.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>add-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${testEnv}</directory>
<targetPath>${basedir}/target/classes</targetPath>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
2.) My second attempt was to add the folder (since the files-to-be-deployed aren't present in Tomcat's classpath yet either) to -Djava.ext.dirs, but it has no effect (I actually suspect that this systemProperties element is misconfigured or otherwise not working at all). See:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.0-beta-1</version>
<configuration>
<tomcatWebXml>${basedir}/src/main/mock/web.xml</tomcatWebXml>
<systemProperties>
<property>
<name>java.ext.dirs</name>
<value>${basedir}/src/main/resources-env/${testEnv}</value>
</property>
</systemProperties>
<path>/licensing</path>
</configuration>
</plugin>
I'm not sure what to attempt next. The heart of the problem seems to be that missing in this plugin is something like Surefire's <additionalClasspathElement> element.
Would the next step be to create a custom catalina.properties and add it to a <configurationDir>? If so, what would catalina.properties need to look like?
Edit: More thorough explanation follows
I understand this question reads somewhat vaguely, so I'll try to elaborate a bit.
My POM uses the webResources functionality of the WAR plugin to copy some environment-specific config files and without using a profile to do it, by copying in a resource named /src/main/resources-env/${env} like so:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
...
<configuration>
...
<webResources>
<!-- Copy Environment-specific resources to classes -->
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
This will copy the (default, DEV) environment resources into the package and currently works fine. Note also that b/c these occur as part of packaging, the tomcat:run goal is never privy to them (which is desired, as the environments differ).
So the problem is this: when the dynamic tomcat:run is executed, the application will fail because its classpath (it looks at target/classes) will lack the needed local workstation environmental config files. All I need to do is get those on the path for tomcat, but would like to do so without adding anything to the command line and definitely without breaking the build's integrity if someone follows up with a mvn package and doesn't clean first.
I hope this is more clear.
I may be missing something but why don't you declare the required dependencies in a profile and use this profile when running Tomcat? I don't get why you would need to put these resources at Tomcat's classpath level.
UPDATE: I'm editing my answer to cover the comment from the OP itself answering my question above.
You're correct, the files really need to be in the webapp classpath, not tomcat's. So how could I make a profile that activate automatically for tomcat:run but without additional cmd line args?
I don't know how to do this without declaring the profile as <activeByDefault> or listing it under the <activeProfiles> (but this is not what I had in mind, I would rather use property activation and call something like mvn tomcat:run -Denv=test, not sure to understand why this is a problem).
And how should I "declare the dependencies" in the profile while ensuring that subsequent invocations never let them into the package WAR via a vanilla mvn package
If the previously mentioned profile is active by default, then you'll need to exclude it if you don't want it, by calling something like mvn package -P !profile-1. A profile can't be magically deactivated for one particular goal (at least, not to my knowledge).
Actually, my understanding is that you really have two different context here: the "testing" context (where you want to include more things in the WAR) and the "normal" context (where you don't want these things to be included). To be honest, I don't know how you could distinguish these two situations without specifying any additional parameter (either to activate a profile or to deactivate it depending on the context). You must have valid reasons but, as I said, I don't really understand why this is a problem. So maybe profiles are not a solution for your situation. But I'd really like to understand why because this seems to be a typical use case for profiles :)
UPDATE2: Having read your comment to the other answer and your update, I realize that my initial understanding was wrong (I though you were talking about dependencies in the maven sense). But, I still think that profiles could help you, for example to customize the <resources> as in this blog post (this is just one way to do, using a property like src/main/resources/${env} in the path is another way to go). But this won't solve all your concerns (like not specifying additional command line params or automagically cleaning the target directory). I don't have any solutions for that.
Add the dependencies element directly to the plugin element.
Here is an example of doing the same with the Jetty plugin from the (still in development) Maven Handbook: http://www.sonatype.com/books/mhandbook-stage/reference/ch06s03.html
Vote for http://jira.codehaus.org/browse/MTOMCAT-77 which addresses this need.
Here's the solution I have in place at the moment.
Special thanks to Pascal's diligent conversation here, but I ultimately decided to make a change to how I was loading my environment-specific config files throughout the goals and now I believe I'm getting most of what I initially wanted.
I removed the config files from <webResources> from the WAR plugin and the test config from <testResources> and am now manually managing the resource-copying with the the maven-resources-plugin to copy them directly into target/classes at the goal they're needed. This way Tomcat can see the config, but the tests aren't broken by having duplicate or differing config files on the path.
It's definitely a mess, but it works. Listing:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>copy-env-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-testEnv-resources</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${testEnv}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-env-resources-again</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources-env/${env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
So a mvn clean install will build and test with ${env} and ${testEnv} appropriately. A mvn -Denv=someLocalConfig tomcat:run (which in my case is identical to my default ${testEnv} will make sure the src/main/resources-env/someLocalConfig gets loaded for Tomcat's dynamic execution, but without requiring that I do a clean before successfully rebuilding.
Like I said, messy that I'm rewriting the same cluster of files to the same target location at each phase, but it accomplishes what I'd meant to.