maven build with war and jar pushing odd artifacts to internal repo - java

I have a maven project where I am building a war file, but I am also using the maven-jar-plugin to build a jar in the same project.
--DISCLAIMER--
I know this is not the 'correct' way to do this, but there are some other issues occurring when splitting this into a jar project and a separate war project with some 3rd party plugins.
I am seeing some strange behavior with this. Below is my project structure.
warproject
-src
--main
---webapp
----WEB-INF
-----web.xml
---java
----com.test.myclass
-----test.java
-pom.xml
When I build this project, i get the correct war and jar file in my target directory, however in my local .m2 repo something strange happens. The war file that is installed is named correctly war-jar-0.0.1-SNAPSHOT.war, however the contents of this file are the contents of my jar file. This also occurs if I do the inverse. i.e. if I setup my project to build a jar and use the maven-war-plugin to build the war, the archives in my target directory are correct, but my local repo has jar file with the contents of my war file. Below is the pom file I am using.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>war-jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<jarName>${project.artifactId}-${project.version}-client</jarName>
</configuration>
<executions>
<execution>
<id>make-a-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
The console output for this is the following, it shows that the jar is being uploaded as the war.
Installing /home/me/work/src/war-jar/target/war-jar-0.0.1-SNAPSHOT.jar to /home/me/.m2/repository/com/test/war-jar/0.0.1-SNAPSHOT/war-jar-0.0.1-SNAPSHOT.war
--UPDATE
I got this working, but I had to change the phase of my 'make-a-jar' execution to install from package. This works fine and the correct artifacts are uploaded, but I am still confused as to why this makes a difference. Obviously the artifact is generated at a different lifecycle phase, and hence is not around at the time of the original install for the project, hence the wrong file is not uploaded. This seems like a 'hack' and I would like to understand why this is behaving this way.

I'm answering my own questions since I didn't get any information that helped me get to my solution. See my update on my original question for my solution.

This also works,
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<!--
When also running maven-jar-plugin correct maven-war-plugin's ID
from "default-war" to "default-jar"
-->
<id>default-jar</id>
<phase>package</phase>
<goals><goal>war</goal></goals>
<configuration>
...
</configuration>
</execution>
</executions>
</plugin>
Refer to http://maven.apache.org/guides/mini/guide-default-execution-ids.html
To figure out why your project behaves as is, analyze the Effective POM.

You need to specify the configurations for the maven-install-plugin to achieve this. Add the following plugin config under <build>.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<packaging>jar</packaging>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<file>
${project.build.directory}/${project.artifactId}-${project.version}.jar
</file>
</configuration>
</execution>
</executions>
</plugin>

Related

Maven: Adding classes from war/web-inf/classes as a jar to war/web-inf/lib

I'm rather new to maven here. I have created a Maven Spring boot project with following structure -
..
<groupId>com.example</groupId>
<artifactId>MavenWeb</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<name>MavenWeb</name>
<description>Maven Test Web Application</description>
<dependencies>
..
As you can see the packaging has been set as war. As such when the war file is generated, my source code's generated .class files are generated in the war/web-inf/classes folder. Rather than it being generated in classes folder, I'd like to generate it as jar file and maintain it in war/web-inf/lib folder.
I'm guessing I need to make use of the maven-jar-plugin for this.
But I'm not sure how to move the generated jar to war/web-inf/lib directory? Is there a simpler alternative to this?
Also how can I restrict the .class files from being generated in war/web-inf/classes folder?
Would really appreciate some pointers. Many thanks.
This is how the build section of pom should be -
<groupId>com.example</groupId>
<artifactId>MavenWeb</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<name>MavenWeb</name>
<description>Maven Test Web Application</description>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archiveClasses>true</archiveClasses>
<webResources>
</webResources>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<packaging>jar</packaging>
<generatePom>true</generatePom>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<file>
${project.build.directory}/${project.artifactId}-${project.version}.jar
</file>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
This would restrict the compiled classes from being generated in classes folder while at the same time generate a thin jar of the compiled classes and add it as web-inf/lib/MavenWeb-0.0.1.jar.

How do I include a "resources" directory alongside (not in with) my built JAR/classes in Maven?

I'm using Maven in IntelliJ and I want to include a 'resources' directory in my build output alongside the JAR and/or in whatever directory IntelliJ uses as the cwd when running my project. I don't want these files in the JAR/Classpath, just alongside the final built project.
The idea is that then, my project can refer to files named things in src/ext-resources/foo.txt as resources/foo.txt.
I'm currently using the following instruction in pom.xml:
<build>
<plugins>
<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>${basedir}/target/resources</outputDirectory>
<resources>
<resource>
<directory>src/main/ext-resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
However, this doesn't appear to actually make it accessible, and doesn't seem to be copying these files at all. At one point, my config resulted in the subdirectories of src/ext-resources being copied into target/classes for some reason, but they aren't being copied into target/resources no matter what.
How do I make maven copy this folder into my final output directory?

Automatically generate Java from .proto with maven/m2e in Eclipse IDE

For my team, I'd like to configure maven/eclipse build to automatically generate Java code from *.proto files (in a project that uses gRPC). Currently one needs to run mvn generate-source or mvn protobuf:compile (as in plugin usage page). Or what is the same add Run configuration to invoke maven goal compile.
Whenever Eclipse Maven project is refreshed (Alt+F5) or IDE is restarted, project is rebuilt but without what should appear in target/generated, thus turning project into red. So one need to generate and refresh project (F5). UPDATE Eclipse has needed source folders configured in .clathpath file.
As I know that should be m2e connector, but I could only find one https://github.com/masterzen/m2e-protoc-connector for the oldest Googles plugin com.google.protobuf.tools:maven-protoc-plugin, that is even not mentioned currently at https://github.com/grpc/grpc-java
We use exactly referenced/recommended
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
that is:
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.1.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.0.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Related:
Linking to generated Java protobuf code in Eclipse
looked at this but that author was using other older, not supported now plugin : Eclipse build loop caused by protobuf generated code (related to Maven Project Builder)
P.P.S That plugin https://github.com/igor-petruk/protobuf-maven-plugin however has continuation as https://github.com/os72/protoc-jar-maven-plugin
Instead of using org.xolstice.maven.plugins:protobuf-maven-plugin my team has used com.github.os72:protoc-jar-maven-plugin to generate the message classes. I believe they are the same since under the hood they all seem to be using the tools from Google.
I am not using any m2e connectors for this plugin (Edit: protoc-jar-maven-plugin's m2e connector is bundled with it so no extra installation is needed, which is why it seemed like I wasn't using one, but technically I was, but this doesn't really matter). Unfortunately the changes in the .proto file are not "automatically" propagated to the generated .java files, you need to manually run Maven or trigger the project to be built in Eclipse (instructions below), but fortunately the target/generated-sources file is not vanishing or emptying or anything strange like what you describe.
If you want to rebuild the .java files from the .proto classes without using mvn clean compile from the command line you can clean the Eclipse project . Project → Clean... → select your project → Select build option (only shows if you have "Build Automatically" from the Project menu is unchecked).
I was able to do this in the latest Eclipse Neon (it will probably work in later ones too, but I don't know for certain).
Below is the POM I am using. I don't think it requires any special explanation, my solution is to simply use a different plugin than the one you are using. (If some explanation is needed I'll be happy to provide it though.)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.jacksonbailey</groupId>
<artifactId>protobuf-m2e-sample</artifactId>
<version>0.1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.1.0.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>3.1.0</protocVersion>
<inputDirectories>
<include>src/main/resources</include>
</inputDirectories>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
for protobuf-maven-plugin
Thanks to sergei-ivanov answer in https://github.com/xolstice/protobuf-maven-plugin/issues/16, that gave link https://github.com/trustin/os-maven-plugin#issues-with-eclipse-m2e-or-other-ides :
One need to download os-maven-plugin-x.x.x.Final.jar (the version as in your pomx.ml) and put it into the <ECLIPSE_HOME>/plugins directory.
After that Eclipse will generate source on project clean, including after Maven -update project... (Alt+F5), but not after Project -> Build (or with default Build Automatically). Also on IDE start it will not compile.
Yes, that is illogical:
Project - Clean will generate and compile Java source
but
Project - Build will not.
P.S. Raised Bug 507412
Both eclipse and vscode can automatically compile proto when changed.
<plugin>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>detect</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.32.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
See: https://github.com/trustin/os-maven-plugin#issues-with-eclipse-m2e-or-other-ides

maven-dependency-plugin copies jars in a wrong way

In my local repository (.m2/repository) I have several jars which I want them to be copied (and referenced) in my project. I have the following pom.xml for the com.google.protobuf artifact:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>groupName</groupId>
<artifactId>groupName.master</artifactId>
<relativePath>../pom.xml</relativePath>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>groupName</groupId>
<artifactId>com.google.protobuf</artifactId>
<name>com.google.protobuf</name>
<version>2.5.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-installed</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
</artifactItem>
</artifactItems>
<outputDirectory>build</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
basically I want this plugin to copy the necessary jar file to the folder called build, which is under the module folder itself. It kinda does copy a jar. However when I click and open the jar, I see no files but only manifests. So the references obviously give error. I checked my local repository and the jar is there, and it is properly formed. So the source is not the problem. Something is wrong with the copying process.
Here are the jars of the same artifact. One is taken from the local repository (above) and the other is the so called copied one to the build folder. As you can see, the copied one lacks the class files which are found under com folder.
Why does the plugin copy this improperly? Anyone had a similar experience?
UPDATE: One thing I noticed is that these two jars have different MANIFEST files inside. Could this be a case that one of the jars is somehow taken from somewhere where it is not supposed to be?
OK, figured out. The problem was I defined the artifact in a wrong way. It should have been:
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<overWrite>true</overWrite>
<type>${project.packaging}</type>
<outputDirectory>build</outputDirectory>
<destFileName>protobuf-java-2.5.0.jar</destFileName>
</artifactItem>
Notice the <name> tag, which was not correct in my pom.xml, therefore the system could not grab the necessary artifact. Also the destFileName tag.
Also, above, this was wrong:
<groupId>groupName</groupId>
<artifactId>com.google.protobuf</artifactId>
<name>com.google.protobuf</name>
If you want to use the one you download from the central repository, you cannot change the groupId or artifactId. They should stay as they are given in the website of the package.
After fixing these, now I am able to see the class files.
Add this plugin pox.xml
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-appCtx</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<!--copy location-->
<outputDirectory>src/main/resources</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<!--file location-->
<directory>${basedir}/lib</directory>
<includes>
<include>test1.jar</include>
<include>test2.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

Maven add jars through systemPath/system but not added to war or anywhere else

I want to add a jar file through the systemPath from the local file-system relative to my project directory structure, not on a remote repository. I added the dependency declaration but maven doesn't do anything else with it.
In the declaration below, I want the jar file copied to my target web-inf/lib directory and also jarred as part of the war file. At present, that doesn't happen. How would I get the jar file copied to my war file?
This is the output from debug maven mode:
DEBUG] cglib:cglib-nodep:jar:2.2:test (setting scope to: compile)^M
DEBUG] Retrieving parent-POM: org.objenesis:objenesis-parent:pom:1.2 for project: null:objenesis:ja
DEBUG] org.objenesis:objenesis:jar:1.2:test (selected for test)^M
DEBUG] org.javap.web:testRunWrapper:jar:1.0.0:system (selected for system)^M
DEBUG] Plugin dependencies for:
...
<dependency>
<groupId>org.javap.web</groupId>
<artifactId>testRunWrapper</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/testRunWrapper.jar</systemPath>
</dependency>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>WebContent</directory>
</resource>
</webResources>
</configuration>
</plugin>
OK, I did this: Note the directory structure at the bottom.
With the approach below, the jar file from the relative project path is treated as a first class citizen like the other jars. The listing below corrects my original problem. With the pom.xml listing below, the jar file is copied to my target directory.
<repositories>
<repository>
<id>JBoss</id>
<name>JBoss Repository</name>
<layout>default</layout>
<url>http://repository.jboss.org/maven2</url>
</repository>
<repository>
<id>my-local-repo</id>
<url>file://${basedir}/lib/repo</url>
</repository>
</repositories>
<dependency>
<groupId>testRunWrapper</groupId>
<artifactId>testRunWrapper</artifactId>
<version>1.0.0</version>
</dependency>
$ find repo
repo
repo/testRunWrapper
repo/testRunWrapper/testRunWrapper
repo/testRunWrapper/testRunWrapper/1.0.0
repo/testRunWrapper/testRunWrapper/1.0.0/testRunWrapper-1.0.0.jar
Using the maven dependency plugin does the job:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
<includeScope>system</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Don't use system. To do what you want, just declare as a regular (compile) dependency and use mvn install:install-file into your local repository. Everything else will work as you want (lib will be copied, etc.) That will mean that the build will only work on your machine, however.
To properly fix this for your (internal) team, you will want to set up a repository (e.g. Artifactory, Nexus, or Archiva). This is almost a must for team use of Maven.
If this is for public (e.g. open source) use you can either mimic a repository via an http server or put up a real repository.
try something like this (using Ant plugin to manually put the jar to output directory):
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy file="${project.basedir}/pathToJAR.jar"
todir="${project.build.directory}/outputFileName/WEB-INF/lib"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
AFAIK, system scoped dependencies are somewhat like those with provided scope and thus are not included in the target artifact. Why don't you install the dependency into your local repository instead?
From the doc:
system
This scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
In case this answer didn't work for you as it didn't for me and you know that system is a bad scope, you can try this solution where you are Installing the jar by using install-plugin (scroll down a bit), which installs the JAR into your actual local Maven-repository. Basically you only need to add this plugin to your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>myGroupId</groupId>
<artifactId>myArtifactId</artifactId>
<version>myVersion</version>
<packaging>jar</packaging>
<file>${basedir}/lib/xxx.jar</file>
</configuration>
</execution>
</executions>
</plugin>
Fill in the appropriate values for groupId, artifactId and version and put your original jar file into the <project-home>/lib-directory and fix file above. You can add more execution-sections, but then don't forget to add ids there, like:
<execution>
<id>common-lib</id>
Everybody who updates from the code-repo needs to call mvn initialize once.
And all Eclipse-enthusiasts may add this to pom.xml, too, to get rid of errors in Eclipse:
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<versionRange>[2.4,)</versionRange>
<goals>
<goal>install-file</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute></execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
The problem with using a reference to the file system is that dependent projects will not be able to globally access this jar file. i.e. the dependent project's ${basedir} is different and thus the .jar file won't be found.
Global repositories on the other hand are universally accessible.

Categories