How can I package a jar with Maven and include some dependencies in WEB-INF/lib? - maven-2

How can I package a jar with Maven and include some dependencies in WEB-INF/lib?
I tried with assembly, but cannot be achieved easier?

Try using the jar-with-dependencies feature of the maven-assembly-plugin:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
This will incorporate all dependencies into your jar. Mark the dependencies that you don't want included in your jar with <scope>provided</scope>, eg:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.4</version>
<scope>provided</scope>
</dependency>

Related

NonExistentClass error when using Mapstruct with Kotlin for generated sources

I want to use Mapstruct to map internal models to models generated by OpenApi3 codegen in a Kotlin project.
When I compile the project, it seems that the Mapstruct is not able to find the sources generated by the OpenApi3 codegen plugin, as the resulting implementation contains a NonExistentClass instead of my OpenApi model.
My plugin configuration is
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
<plugin>jpa</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>kapt</id>
<phase>process-sources</phase>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>process-test-sources</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
It seems that the problem is related to kapt finding the generated Java sources.
Is my configuration broken or am I encountering a limitation of the kotlin annotation processor?
EDIT: A simple example to reproduce this can be found here: https://github.com/tobisinghania/kotlin-openapi3-mapstruct-failure
The issue is due to the missing <sourceDir>target/generated-sources/openapi/src/main/java</sourceDir> in the kotlin maven plugin configuration
I've made a Pull Request on your repo,

AspectJ pointcut expression for Jackson DeserializationContext reportMappingException

I am trying to write a pointcut to have an around advice around: com.fasterxml.jackson.databind.DeserializationContext.reportMappingException() method.
This is what I have so far and it's not working i.e. maven complains:
[WARNING] advice defined in com.charter.aesd.videocatalog.client.interceptor.ContactManagerLogger has not been applied [Xlint:adviceDidNotMatch]
/Users/rhasija/dev/projects/video/videocatalog-middle/client/src/main/java/com/charter/aesd/videocatalog/client/interceptor/ContactManagerLogger.java:36
Trial 1:
#Pointcut("execution(* com.fasterxml.jackson.databind.DeserializationContext+.*(..))")
public void servicePointcut() {}
Trial 2:
#Pointcut("execution( * com.fasterxml.jackson.databind.*.*(..) )")
public void servicePointcut() {}
Below is my pom.xml. Is it not possible to have a pointcut to an external library via AspectJ?
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
....
</dependencies>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<includes>
<include>**/*.java</include>
<include>**/*.groovy</include>
</includes>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<!--suppress MavenModelInspection -->
<goal>compile</goal>
<!--suppress MavenModelInspection -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>info.ponge.julien.hacks.guiceaspectj.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<!--suppress MavenModelInspection -->
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Have you tried configuring the maven plugin? Add:
<configuration>
....
<weaveDependencies>
<weaveDependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</weaveDependency>
<weaveDependencies>
<configuration>
Weaving already compiled JAR artifacts
The weaveDependencies corresponds to ajc -inpath and bear in mind that what it does is take the classes in the jar file, wave them, and include them in the output target/classes.
The AspectJ compiler/weaver
Maven aspectj:compile
You could use load-time weaving as well, injecting aspect instructions to the byte code during class loading.

How to specify the JAXB version in maven-jaxb2-plugin?

I need to use the latest version jaxb: 2.2.4-1, but maven or maven-jaxb2-plugin seems to pick up the one from the JDK.
I tried specifying the version like this:
<configuration>
<specVersion>2.2</specVersion>
...
</configuration>
but the logs read:
[INFO] [jaxb2:generate {execution: common}]
[INFO] Started execution.
[INFO] JAXB API is loaded from the [jar:file:/opt/jdk1.6.0_24/jre/lib/rt.jar!].
[INFO] Detected JAXB API version [2.1].
I tried to add dependencies to the correct versions of javax.xml.bind:jaxb-api and com.sun.xml.bind:jaxb-impl, but that didn't help.
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.4-1</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>common</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<specVersion>2.2</specVersion>
...
</configuration>
</execution>
</executions>
</plugin>
</plugins>
I also tried using maven-jaxb22-plugin but it also didn't work.
The following code is adapted from the default webapp that netbeans generates. It uses the dependency plugin to copy the jars to a temporary folder and specifies this folder as the endorsed directory to the compiler so it overrides the implementation in the jdk.
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.4</version>
<type>jar</type>
</artifactItem>
<artifactItem>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.4-1</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I attempted to use Jörn's solution, but it looks like maven-jaxb2-plugin went ahead and used the rt.jar version anyway, as I got the telling message from the plugin: [INFO] JAXB API is loaded from the [jar:file:/C:/jdk1.6.0_25/jre/lib/rt.jar!].
My unsuccessful version of the solution is slightly different in how it uses the dependency plugin, but that's the one part of the build that succeeds...
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<v.jaxb2-api>2.2.4</v.jaxb2-api>
<v.jaxb2-impl>2.2.4-1</v.jaxb2-impl>
<v.jaxb2-xjc>2.2.4-1</v.jaxb2-xjc>
<v.jaxb2-basics-jaxb>2.1.13.MR2</v.jaxb2-basics-jaxb>
</properties>
...
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>validate</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<excludeTransitive>true</excludeTransitive>
<includeArtifactIds>jaxb-api,jaxb-impl</includeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<fork>true</fork>
<meminitial>256m</meminitial>
<maxmem>768m</maxmem>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
hey just I want to save time of the people.
for the people who work on jaxb-impl, the version jaxb-impl 2.2.4-1 that meant to fix a bug of the version 2.2.4, the pom of istack-commons-runtime under the META-INF Folder contain a reference to its parent pom 2.4-SNAPSHOT when it should be jsut 2.4, due this version isn't a snapshot.
<parent>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons</artifactId>
<version>2.4-SNAPSHOT</version>
</parent>
so if you don't want to work with snapshot you will smash with this error, unless you want to add everything on your local repository you may have to update manually this version into the pom on the jar.
cheers,
Manuel.

Maven: add a folder or jar file into current classpath

I am using maven-compile plugin to compile classes. Now I would like to add one jar file into the current classpath. That file stays in another location (let's say c:/jars/abc.jar . I prefer to leave this file here). How can I do that?
If I use classpath in the argument:
<configuration>
<compilerArguments>
<classpath>c:/jars/abc.jar</classpath>
</compilerArguments>
</configuration>
it will not work because it will override the current classpath (that includes all the dependencies)
This might have been asked before. See Can I add jars to maven 2 build classpath without installing them?
In a nutshell: include your jar as dependency with system scope. This requires specifying the absolute path to the jar.
See also http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
The classpath setting of the compiler plugin are two args. Changed it like this and it worked for me:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgs>
<arg>-cp</arg>
<arg>${cp}:${basedir}/lib/bad.jar</arg>
</compilerArgs>
</configuration>
</plugin>
I used the gmavenplus-plugin to read the path and create the property 'cp':
<plugin>
<!--
Use Groovy to read classpath and store into
file named value of property <cpfile>
In second step use Groovy to read the contents of
the file into a new property named <cp>
In the compiler plugin this is used to create a
valid classpath
-->
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.12.0</version>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<!-- any version of Groovy \>= 1.5.0 should work here -->
<version>3.0.6</version>
<type>pom</type>
<scope>runtime</scope>
</dependency>
</dependencies>
<executions>
<execution>
<id>read-classpath</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
</execution>
</executions>
<configuration>
<scripts>
<script><![CDATA[
def file = new File(project.properties.cpfile)
/* create a new property named 'cp'*/
project.properties.cp = file.getText()
println '<<< Retrieving classpath into new property named <cp> >>>'
println 'cp = ' + project.properties.cp
]]></script>
</scripts>
</configuration>
</plugin>
From docs and example it is not clear that classpath manipulation is not allowed.
<configuration>
<compilerArgs>
<arg>classpath=${basedir}/lib/bad.jar</arg>
</compilerArgs>
</configuration>
But see Java docs (also https://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/tooldocs/solaris/javac.html)
-classpath path Specifies the path javac uses to look up classes needed to run javac or being referenced by other classes you are
compiling. Overrides the default or the CLASSPATH environment variable
if it is set.
Maybe it is possible to get current classpath and extend it,
see in maven, how output the classpath being used?
<properties>
<cpfile>cp.txt</cpfile>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>build-classpath</id>
<phase>generate-sources</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputFile>${cpfile}</outputFile>
</configuration>
</execution>
</executions>
</plugin>
Read file (Read a file into a Maven property)
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def file = new File(project.properties.cpfile)
project.properties.cp = file.getText()
</source>
</configuration>
</execution>
</executions>
</plugin>
and finally
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgs>
<arg>classpath=${cp}:${basedir}/lib/bad.jar</arg>
</compilerArgs>
</configuration>
</plugin>
We mixed two of the answers found here to solve a similar problem. Our project needs a JAR only in compile stage, but add a local dependency, using system scope, it is unuseful because Maven refuse the artifact publication with an error related to a missing dependency.
The snippets used are the following:
<properties>
<classpathfile>${basedir}/classpathfile.classpath</classpathfile>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>build-classpath</id>
<phase>generate-sources</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputFile>${classpathfile}</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def file = new File(project.properties.classpathfile)
project.properties.originalClassPath = file.getText()
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<compilerArgs>
<arg>-cp</arg>
<arg>${originalClassPath}${path.separator}${basedir}/../../../bin/POM_RUNTIME_PLACEHOLDER/ExtraJar.jar</arg>
</compilerArgs>
</configuration>
</plugin>
Maven is able to compile and successfully deploy the artifacts.
If anyone is interested the full POM is available in GitHub under project NuReflector, defaultPOM.template under src/NuReflector.

Share test resources between maven projects

There is a clear solution for sharing the common test code between maven projects using test-jar goal of maven-jar-plugin plugin (see here).
I need to do the similar thing with test resources, in particular, I want test resources of project A be available in the classpath of project B during testing.
For project A one need to declare:
<!-- Package and attach test resources to the list of artifacts: -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<jar destfile="${project.build.directory}/test-resources.jar">
<fileset dir="${project.basedir}/test-resources" />
</jar>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/test-resources.jar</file>
<type>jar</type>
<classifier>test-resources</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
And in project B it will be normal dependency:
<dependency>
<groupId>myproject.groupId</groupId>
<artifactId>myartifact</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>test-resources</classifier>
<scope>test</scope>
</dependency>
Question: Should it work in all cases? Is it possible to pack resources without maven-antrun-plugin (using more 'lightweight' plugin)?
Just use jar:test-jar and declare the resulting JAR as a dependency (refer to this guide for more details). And while I don't understand the problem of having resources and classes in this jar, you can always exclude all .class files:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>**/*.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
And to use it:
<project>
...
<dependencies>
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
Accepted answer helped me, but it's not quite accurate in case you need regular jar of same project as well. It will delete *.class files from both jars.
Settings below translates to something like:
create me 2 jars: 1 regular, 1 test;
remove *.class files, but only from test jar
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*.class</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
Using maven-dependency-plugin we can put the resource needed in the right directory, only modifying the pom on dependent project is needed:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>generate-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>dependeeGroupId</groupId>
<artifactId>dependeeArtifactId</artifactId>
<version>dependeeVersion</version>
<type>test-jar</type>
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
<includes>resourceNeeded.txt</includes>
<overWrite>true</overWrite>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
type is used to get test resource
outputDirectory is used to put the resource usable in tests
Documentation here: https://maven.apache.org/plugins/maven-dependency-plugin/unpack-mojo.html
There is already a goal to build a test jar from maven.
Assuming you need something a little more flexible, you can use the jar plugin to package your test resources and run that goal with the main package goal with something like this.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>test-resources</classifier>
<includes>
<include>**/*.whatever-you-want</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
Whatever you want bundled would be added to the project-name-version-test-resources.jar when the jar goal is run.
You could then include it in a project via the same dependency you use above.