I'm creating a custom plugin for maven. Normally, when you run a normal Java program that depends on some .jar files, you put it in the command line as a classpath. In my plugin, there are some things it needs to know about that are in other .jar files.
When compiling the plugin for maven, how do I add classpaths to my custom maven plugin? Would I add it as a dependency in the pom.xml?
You can add things on the classpath of a plugin via defining dependencies for a plugin which works like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.1</version>
<dependencies>
<dependency>
<groupId>checkstyle</groupId>
<artifactId>checkstyle</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
</plugin>
Apart from that it sounds strange that you need to define dependencies of a plugin during the runtime of the plugin.
Related
After creating my war file with mvn package, war file include web/INF lib folder. In that folder, there are some jars which I did not prefer because of the versions of jar.
I cannot manage the version of these jars directly. Some spring plugins/packages manages this.
I tried to increase the versions of plugins which in pom.xml but it did not bring exact version which I need.
How can I change it with mvn commands or pom.xml?
You can get a clear view of the hierarchy of dependencies with this command:
mvn dependency:tree
To exclude a jar from the war, you need to specify the scope with "provided" value. So, you need to add (for a dependency of a dependency) or change the corresponding dependency block:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
Another way is to configure the plugin that does the magic:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<packagingExcludes>WEB-INF/lib/spring-aop-5.3.19.jar</packagingExcludes>
</configuration>
</plugin>
Your project have some jars in web/INF lib,there can not change with mvn.
You should find this jars what you want version in internet,download and replace.
But I suggest you use mvn manage this jars.
My project includes the nd4j-native-platform dependency, which includes .jars for windows, linux, and mac. The app is developed on windows/mac machines then deployed to Linux, so I'd like to save space on deployment by excluding these other platform jars that take up > 400 MB when the .war is built. Tl;dr, I want to exclude all the .jars that don't end with linux-x86_64.
Dependency in pom:
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-native-platform</artifactId>
<version>1.0.0-beta7</version>
<classifier>linux-x86_64</classifier>
</dependency>
I don't see any way to exclude them by classifier in the dependency tag, it seems you can only exclude by groupId and artifactId. I also tried using packagingExcludes and warSourceExcludes in the .war plugin, but that didn't do anything:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<packagingExcludes>
WEB-INF/lib/nd4j-native-1.0.0-beta7-windows-x86_64.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-android-x86.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-macosx-x86_64.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-android-x86_64.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-linux-ppc64le.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-android-arm64.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-android-arm.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-windows-x86_64.jar,
WEB-INF/lib/nd4j-native-1.0.0-beta7-linux-armhf.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-windows-x86.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-windows-x86.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-linux-armhf.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-linux-ppc64le.jar,
WEB-INF/lib/openblas-0.3.9-1-1.5.3-linux-arm64.jar
</packagingExcludes>
</configuration>
</plugin>
Using Maven 3.6.3.
The correct way to deal with this for most things that use JavaCPP is to set the javacpp.platform property.
When building with mvn -Djavacpp.platform=linux-x86_64 you will get only that specific platform and nothing else. This will also apply to all other transitive dependencies, e.g. opencv.
You can try running mvn -Djavacpp.platform=linux-x86_64 dependency:tree to see that it works.
I've see you can add dependencies element of the plugin element in a pom.
Question: What's for? Should'nt all the lib used by a plugin be include inside it? Do it surcharge some lib used by the plugin?
<plugin>
<groupId>org.raml.plugins</groupId>
<artifactId>raml-jaxrs-maven-plugin</artifactId>
<version>1.3.4</version>
<dependencies>
<dependency>
<groupId>org.raml</groupId>
<artifactId>raml-parser-2</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
From official Maven POM Reference documentation:
dependencies: Dependencies are seen a lot within the POM, and are an element under all plugins element blocks. The dependencies have the same structure and function as under that base build. The major difference in this case is that instead of applying as dependencies of the project, they now apply as dependencies of the plugin that they are under. The power of this is to alter the dependency list of a plugin, perhaps by removing an unused runtime dependency via exclusions, or by altering the version of a required dependency.
That is, you can exclude some libraries from the plugin classpath or override certain versions, within the scope of that specific plugin.
Adding dependencies to a plugin would not alter the classpath of the application being built. The dependencies for a plugin is an entry point for further configurability, to directly change its classpath.
In most of the cases you would not need to work at that level of granularity, but indeed is quite useful in some cases and some plugin would actually need or recommend to add specific dependencies, for example plugins working on transformation or code generation (WSDL to Java, e.g.) would probably need a further dependency (you choose which one and which version) and so on.
A further official example is provided by the official Maven - Guide to configure plugins documentation:
You could configure the dependencies of the Build plugins, commonly to use a more recent dependency version.
For instance, the Maven Antrun Plugin version 1.2 uses Ant version 1.6.5, if you want to use the latest Ant version when running this plugin, you need to add <dependencies> element.
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
...
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
...
</project>
Another example is provided by the official Exec Maven Plugin documentation in case you want to use its java goal to execute a Java program and you actually need to add libraries to its classpath but you don't want to alter the classpath of the application under build: this is a much cleaner and reasonable approach.
Dependency in plugin element allows you to define a specific version you will like the plugin to use.
Here is a good example on maven.apache.org
For instance, the Maven Antrun Plugin version 1.2 uses Ant version 1.6.5, if
you want to use the latest Ant version when running this plugin, you need to add <dependencies> element
I am writing a project for acceptance testing and for various reasons this is dependent on another project which is packaged as a WAR. I have managed to unpack the WAR using the maven-dependency-plugin, but I cannot get my project to include the unpacked WEB-INF/lib/*.jar and WEB-INF/classes/* to be included on the classpath so the build fails. Is there a way to include these files into the classpath, or is there a better way of depending on a WAR?
Many thanks.
There's another option since maven-war-plugin 2.1-alpha-2. In your WAR project:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
This creates a classes artifact which you can use in the acceptance tests project with:
<dependency>
<groupId>your-group-id</groupId>
<artifactId>your-artifact-id</artifactId>
<version>your-version</version>
<classifier>classes</classifier>
</dependency>
Indeed, by design, Maven doesn't resolve transitive dependencies of a war declared as dependency of a project. There is actually an issue about that, MNG-1991, but it won't be solved in Maven 2.x and I'm not sure that I don't know if overlays allow to workaround this issue. My understanding of the suggested solution is to duplicate the dependencies, for example in a project of type pom.
(EDIT: After some more digging, I found something interesting in this thread that I'm quoting below:
I have been helping out with the development of the AppFuse project over
the last month where we make heavy use of the war overlay feature in the
Maven war plugin. It is a really nifty feature!
To get max power with war overlays I have developed the Warpath plugin
that allows projects to use war artifacts as fully fledged dependencies.
In brief:
1) The contents of the /WEB-INF/classes directory in the war dependency
artifacts can be included in the project's classpath for normal compile,
etc tasks.
2) Transitive dependencies from the war dependency artifacts become
available for use by other plugins, e.g. compile and ear - so no more
having to include all the dependencies when creating skinny wars!
The plugin has now been actively used in the AppFuse project for the
last few months, and I feel it is at a point where it is both usable and
stable.
Would the war plugin team be interested in including the warpath
functionality inside the war plugin? It would seem to be the most
natural place to host it.
So, I don't have any experience with it, but the maven warpath plugin actually looks nice and simple and is available in the central repo. To use it,include the following plugin configuration element in your pom.xml file:
[...]
<build>
<plugins>
<plugin>
<groupId>org.appfuse</groupId>
<artifactId>maven-warpath-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>add-classes</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
And add the war dependencies you want included in the classpath as warpath type dependencies:
[...]
<dependencies>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>warpath</type>
</dependency>
</dependencies>
[...]
Both the war and warpath dependency types are needed: the war type is used by the Maven war plugin to do the war overlay, the warpath type is used by the Warpath plugin to determine the correct list of artifacts for inclusion in the project classpath.
I'd give it a try.)
Use overlays. First, your test project need to have also packaging war.
Declare dependency of war project you want to test:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>your-project-arftifactId</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
then configure maven-war-plugin overlay:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webresources</directory>
<filtering>true</filtering>
</resource>
</webResources>
<overlays>
<overlay/>
<overlay>
<groupId>your.group</groupId>
<artifactId>your-project-artifactId</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
In the above example in test project I overwrite webresources configuration files (like conxtext etc.).
EDIT: This solution wasn't tested with Maven 3.
Good point, Justin. That got me actually solving my problem, namely: including a war into an assembly AND including all its transitive dependencies.
I could not duplicate the war-dependency as 'jar' as you suggested since the assembly plugin would not find a jar referenced by that groupId/artefactId, but
duplicating the war-dependency as type pom
works!
The war and its transitive dependencies are not included in the assembly.
To exclude the (now also appearing) pom file I had to add an exclude element like this:
<excludes>
<exclude>*:pom</exclude>
</excludes>
into my assembly.xml file.
I think this could also be a workaround for the original question of this thread.
If you list the dependency on the war project as a jar dependency it seems to pickup the required jars/resources. I'm using Maven 2.2 + m2eclipse.
Need to be pointed in the right direction on this perhaps, but if I add a "provided" dependency that is not included in the tomcat set of provided dependencies, running tomcat7:run from within eclipse fails with a classnotfoundexception on the class from the provided scope jar.
It needs to "provided" because it's a custom jar from a separate project that I've run mvn install on and for production am copying the jar to the $CATALINA_BASE/shared directory so that it's available (as a singleton) across applications/webapps.
<dependency>
<groupId>IndexFileAccessTracker</groupId>
<artifactId>IndexFileAccessTracker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
Only way I see (with my limited knowledge of Maven and the Tomcat7 plugin) is to change the scope to compile when running tomcat from the plugin in Eclipse and then change the scope back to provided when running the package goal.
Are there solutions to this? I tried adding the dependency to the the tomcat maven plugin (keeping the main maven dependency as provided but got the same class not found error:
<!-- For Maven Tomcat Plugin -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/CounterWebApp</path>
</configuration>
<dependencies>
<dependency>
<groupId>IndexFileAccessTracker</groupId>
<artifactId>IndexFileAccessTracker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</plugin>
Again, it needs to be provided in the main Maven dependency because I don't want it included in the deployed WAR.
Resolved by using profiles, similar to https://stackoverflow.com/a/5951630
...
</dependencies>
<profiles>
<profile>
<id>runineclipse</id>
<dependencies>
<dependency>
<groupId>IndexFileAccessTracker</groupId>
<artifactId>IndexFileAccessTracker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</profile>
</profiles>
<build>
...
Then in my run/debug configuration just added runineclipse to the Profiles: box.
(On a side note, to do step through debugging I had to manually add the project to the Source tab.)
The build configuration was just the same package in the Goals: box; and I left the original dependency to have scope provided.
The tomcat7-maven-plugin and its run goal
Requires dependency resolution of artifacts in scope: test
Everythig that is on the compile classpath is also on the test classpath.
Thats why it is working with scope compile.
So the solution in your case would be to mark your dependency as test what even is (imo) semantically correct.
This will make the library available at local test-time, but not in the final artifact.