I have a multi-module build creating multiple artifacts with package type "bundle".
Some of them create some information in the META-INF directory during compile time, some don't.
I tried to define an instruction in the parent pom.xml that adds the META-INF directory as a resource to the bundle.
Unfortunately this fails for those artifacts not creating the META-INF directory during the build time.
I tried to avoid defining this rule on all modules that currently DO creating the META-INF directory since
There is a lot and
maybe the others will create the META-INF directory in the future and this will require future developers to know that they have to add this directory as a resource now.
Is it somehow possible to make this "include-resource" instruction optional, meaning it ignores this resource if it's missing?
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<instructions>
<Include-Resource>META-INF=${project.build.outputDirectory}/META-INF</Include-Resource>
</instructions>
</configuration>
</plugin>
Prefixing the resource pattern with - should suffice, e.g.:
<Include-Resource>-META-INF=${project.build.outputDirectory}/META-INF</Include-Resource>
Documentation here.
Related
TL; DR
Maven's Resources plugin doesn't seem to respect excludes elements in the resource configuration.
Setting
I have a large Java/Dart project where I need to deploy a WAR file that has both my UI and my backend in separate JARs. I want to cut down on the size of the deployed file, and I want to drop certain folders from the WAR. Based on the plugin documentation, I thought I could simply set excludes in my plugin configuration, and it won't copy over the unnecessary folders. However, it seems the Resources plugin is outright ignoring these, despite, the Maven model package including a setExcludes function.
Current Attempts
So far, I've tried two main approaches. My configuration is as follows:
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}</outputDirectory>
<resources>
<resource>
<directory>src/main/webapp</directory>
<excludes>
<exclude>web.xml</exclude>
<exclude>appengine-web.xml</exclude>
<exclude>**/web/_el/*</exclude>
<exclude>WEB-INF/pages/frontend/**</exclude>
<exclude>**/_el/js/frontend/**</exclude>
<exclude>**/_el/dart/app/dashboard/lib/**</exclude>
<exclude>**/_el/dart/app/dashboard/.dart_tool/**</exclude>
</excludes>
</resource>
</resources>
</configuration>
I tried to use this config inside the execution element, as well as outside from directly under the plugin element, but both times it was ignored, and everything in the webapp directory was copied over mindlessly.
On a hunch, I did try setting filtering to true, but that just ate up all the memory in my computer, and it didn't even work - what it did process was copied over.
I also tried using the Shade plugin, but gave up on that pretty quickly, as the DontIncludeResourceTransformer only permits suffix-filtering, which is not adequate for my use case.
Question
So what am I doing wrong? Based on the docs, I believe the plugin should respect my excludes list and skip the vast majority of files, but it's evidently not doing that.
You need to use apache **maven war plugin**.
The WAR Plugin is responsible for collecting all artifact dependencies, classes and resources of the web application and packaging them into a web application archive.
It is possible to include or exclude certain files from the WAR file, by using the and configuration parameters. They each take a comma-separated list of Ant file set patterns. You can use wildcards such as ** to indicate multiple directories and * to indicate an optional part of a file or directory name.
Here is an example where we exclude all JAR files from WEB-INF/lib:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
https://maven.apache.org/plugins/maven-war-plugin/examples/including-excluding-files-from-war.html
It looks like it is possible to get the path/to/a/dependency.jar as an expandable variable within a Maven pom.xml: see Can I use the path to a Maven dependency as a property? You can expand, e.g., an expression into a string like /home/pascal/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar.
What I want instead of the full path to the dependency JAR within my local Maven repository is just the bare name of the JAR, for example junit-3.8.1.jar.
So for example, within my pom.xml, I would like to be able to use a value like ${maven.dependency.junit.junit.jar.name} to expand to junit-3.8.1.jar.
Can I do this, and how?
You can use the maven-antrun-plugin to get the file name of a dependency. Ant has a <basename> task which extracts the file name from a path. As described in Can I use the path to a Maven dependency as a property? the full path name of a dependency is available in ant as ${maven.dependency.groupid.artifactid.type.path}. This enables us to extract the file name with the ant task like this:
<basename file="${maven.dependency.groupid.artifactid.type.path}" property="dependencyFileName" />
This stores the file name in a property named dependencyFileName.
In order to make this property availbable in the pom, the exportAntProperties configuration option of the maven-antrun-plugin needs to be enabled. This option is only available as of version 1.8 of the plugin.
This example shows the plugin configuration for retrieving the artifact file name of the junit dependency:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>initialize</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<tasks>
<basename file="${maven.dependency.junit.junit.jar.path}"
property="junitArtifactFile"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
No, I'm sorry to say that it isn't possible. So, you have two options before you.
1) modify the maven source code and contribute the modification.
2) write your own plug-in.
I recommend the second option. Writing plug-ins is not that hard. As a philosophical principal, select a frequently-used plug-in which has functionality close to what you want to accomplish. Read and understand the code, and then modify it to do what you desire.
So for your example, you might look at the filter plugin. There's also some interesting syntax going on in the Ant plugin. It allows you to name dependencies and get those jar filenames into the embedded Ant script.
Good luck. :-)
As a more practical alternative, you might just break down and manually code the property value with the exact version number you're using. You're not going to switch the version number that often, right? And this is only one jar you're dealing with, right?
According to the Spring boot documentation, it's possible to define additional command when using a remote shell based on Crash.
Default locations for these commands are classpath*:/commands/,classpath*:/crash/commands/
A property can be used to override the default locations but in the provided example, the custom command is located in resources.
In my opinion, custom commands (at least java commands) shouldn't be located in resources but in src/main/java.
It works fine when defining a custom path in resources but how can I define a custom path in src/main/java? Didn't find a way to do it for now!
If they're under src/main/java, they'll be compiled automatically which is not what you need. My solution was to simulate that directory as a resources folder, which in short translates to:
configure the compiler plugin to ignore that particular folder
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<excludes>
<exclude>crash/commands/*</exclude>
</excludes>
</configuration>
</plugin>
copy the files just like any regular resources in the target directory
<resource>
<directory>src/main/java/crash/commands</directory>
<targetPath>crash/commands</targetPath>
<filtering>false</filtering>
</resource>
Minor update & disclaimer:
As you may already know, there are a couple of closures which are executed on login/logout. At least with v1.3.1, which is what I'm blindly inheriting from spring-boot, it will pick the first login.groovy it finds in the classpath. My project's artifact is packaged in an RPM along with all the other dependencies. Since its name begins with r, it comes after crash.shell-1.3.1.jar which is where the defaults reside, so I had to do the following small hack to make it pick up my own scripts instead of the default ones:
<!-- hack to make CRaSH pick up login.groovy from our jar instead of the default one -->
<finalName>0_${project.artifactId}-${project.version}</finalName>
You can try to put your command at src/main/resources/commands/
Attempting to modify an existing Java/Tomcat app for deployment on Heroku following their tutorial and running into some issues with AppAssembler not finding the entry class. Running target/bin/webapp (or deploying to Heroku) results in Error: Could not find or load main class org.stopbadware.dsp.Main
Executing java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main runs properly however. Here's the relevant portion of pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>org.stopbadware.dsp.Main</mainClass>
<name>webapp</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
My guess is mvn package is causing AppAssembler to not use the correct classpath, any suggestions?
Your artifact's packaging must be set to jar, otherwise the main class is not found.
<pom>
...
<packaging>jar</packaging>
...
</pom>
The artifact itself is added at the end of the classpath, so nothing other than a JAR file will have any effect.
Try:
mvn clean package jar:jar appassembler:assemble
Was able to solve this by adding "$BASEDIR"/classes to the CLASSPATH line in the generated script. Since the script gets rewritten on each call of mvn package I wrote a short script that calls mvn package and then adds the needed classpath entry.
Obviously a bit of a hack but after a 8+ hours of attempting a more "proper" solution this will have to do for now. Will certainly entertain any more elegant ways of correcting the classpath suggested here.
I was going through that tutorial some time ago and had very similar issue. I came with a bit different approach which works for me very nicely.
First of all, as it was mentioned before, you need to keep your POM's type as jar (<packaging>jar</packaging>) - thanks to that, appassembler plugin will generate a JAR file from your classes and add it to the classpath. So thanks to that your error will go away.
Please note that this tutorial Tomcat is instantiated from application source directory. In many cases that is enough, but please note that using that approach, you will not be able to utilize Servlet #WebServlet annotations as /WEB-INF/classes in sources is empty and Tomcat will not be able to scan your servlet classes. So HelloServlet servlet from that tutorial will not work, unless you add some additional Tomcat initialization (resource configuration) as described here (BTW, you will find more SO questions talking about that resource configuration).
I did a bit different approach:
I run a org.apache.maven.plugins:maven-war-plugin plugin (exploded goal) during package and use that generated directory as my source directory of application. With that approach my web application directory will have /WEB-INF/classes "populated" with classes. That in turn will allow Tomcat to perform scanning job correctly (i.e. Servlet #WebServlet annotations will work).
I also had to change a source of my application in the launcher class:
public static void main(String[] args) throws Exception {
// Web application is generated in directory name as specified in build/finalName
// in maven pom.xml
String webappDirLocation = "target/embeddedTomcatSample/";
Tomcat tomcat = new Tomcat();
// ... remaining code does not change
Changes to POM which I added - included maven-war-plugin just before appassembler plugin:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
...
Please note that exploded goal is called.
I hope that small change will help you.
One more comment on that tutorial and maven build: note that the tutorial was written to show how simple is to build an application and run it in Heroku. However, that is not the best approach to maven build.
Maven recommendation is that you should adhere to producing one artifact per POM. In your case there are should two artifacts:
Tomcat launcher
Tomcat web application
Both should be build as separate POMs and referenced as modules from your parent POM. If you look at the complexity of that tutorial, it does not make much sense to split that into two modules. But if your applications gets more and more complex (and the launcher gets some additional configurations etc.) it will makes a lot of sense to make that "split". As a matter of fact, there are some "Tomcat launcher" libraries already created so alternatively you could use of one them.
You can set the CLASSPATH_PREFIX environment variable:
export CLASSPATH_PREFIX=target/classes
which will get prepended to the classpath of the generated script.
The first thing is that you are using an old version of appassembler-maven-plugin the current version is 1.3.
What i don't understand why are you defining the
<assembleDirectory>target</assembleDirectory>
folder. There exists a good default value for that. So usually you don't need it. Apart from that you don't need to define an explicit execution which bounds to the package phase, cause the appassembler-maven-plugin is by default bound to the package phase.
Furthermore you can use the useWildcardClassPath configuration option to make your classpath shorter.
<configuration>
<useWildcardClassPath>true</useWildcardClassPath>
<repositoryLayout>flat</repositoryLayout>
...
</configruation>
And that the calling of the generated script shows the error is depending on the thing that the location of the repository where all the dependencies are located in the folder is different than in the generated script defined.
I have a project that consists of several Maven modules which are all children of a parent module.
I have the parent set up to use checkstyle and the child modules all inherit this behaviour correctly. I would like all the child modules to use the parents suppression file defined in its plugin.
I define a property checkstyle.suppression which is used in the checkstyle plugin
<properties>
<checkstyle.suppressions>${basedir}\src\checkstyle\suppressions.xml</checkstyle.suppressions>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.2</version>
<configuration>
<configLocation>config/sun_checks.xml</configLocation>
<suppressionsLocation>${checkstyle.suppressions}</suppressionsLocation>
<suppressionsFileExpression>${checkstyle.suppressions}</suppressionsFileExpression>
</configuration>
</plugin>
</plugins>
Which works fine for the parent but all the child modules try to find the file in their basedir which does make sense.
I am sure there must be a simple solution I am missing but is there a way to define this location so that all the child modules will use the parent location without hard coding it?
The answers above are dangerous. I maintain that each project should be self contained, so referring to files external to it is going to break a build sooner or later. Checkstyle can take a url for the file but that means you can't build offline. A better approach is to package your file (can also add pmd.xml) into a jar and then add that jar to the classpath of the checkstyle (or pmd) plugin. I have an example of it here and more about overridding a plugin classpath here
The plugin's documentation mentions a similar use case here:
http://maven.apache.org/plugins/maven-checkstyle-plugin/examples/multi-module-config.html
Have you tried defining the property like this in the parent pom or redefining it in the childrens?
<properties>
<checkstyle.suppressions>${parent.project.basedir}\src\checkstyle\suppressions.xml</checkstyle.suppressions>
</properties>
If the parent isn't going to run checkstyle, you might just be able to rewrite it to
<properties>
<checkstyle.suppressions>..\..\src\checkstyle\suppressions.xml</checkstyle.suppressions>
</properties>
Or something like this. Or you could put something in settings.xml to point everything to an system wide config directory.
While it might not be recommended, you can have use a boot-strap or set-up project or task put a copy of the suppressions.xml file to a location specified by a property in settings.xml and then always refer to it by that locations.