Is there anyway to get at runtime the full artifact version / build number generated by the maven deploy plugin of my war at runtime?
It'd be ok if the maven process generated and packaged up a properties file with the value.
Keep in mind that my project generates unique (timestamped) artifact versions for every deploy.
Try this:
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries/>
<addDefaultSpecificationEntries/>
</manifest>
</archive>
</configuration>
That will add the maven details from the pom that build the war into the MANIFEST.MF file, which you can read at runtime.
Another way that I occasionally use is to use filtering of properties files, and drop the pom values into there - useful if you already have a property file/config loading mechanism in place.
Then, when it's deployed, which uses the same values from the pom, you're fine.
-Chris
You could package it up in your Manifest file using maven-jar-plugin which can be read through you application wherever you need.
Here is the basic configuration which would write the properties in pom.xml to your Manifest file.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>false</addClasspath>
</manifest>
<manifestEntries>
<Implementation-Vendor>Vendor Name</Implementation-Vendor>
<Implementation-Version>${revision}</Implementation-Version>
<Build-Timestamp>${timestamp}</Build-Timestamp>
<Build-Number>${release}_${revision}</Build-Number>
</manifestEntries>
</archive>
</configuration>
<executions>
<!-- your jar executions here -->
</executions>
</plugin>
where your property values would be defined in pom.xml as :
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<release>DevelopmentBuild</release>
<revision>Some Value</revision>
<properties>
EDIT:
This can be done using maven-war-plugin also.
You can get more information on WAR Manifest Customization Here.
Related
I'd need Maven war plugin to use a custom MANIFEST.MF. As I read from the documentation you can put your MANIFEST.MF file in src/main/resources/META-INF/ and add the following configuration to your pom.xml file:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
However I see the MANIFEST.MF added in the WebRoot/META-INF is the default one. I can't find what is going wrong. Any suggestion or link to github projects where it does work ?
Thanks
First in your configuration you missed the <groupid>!
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
...
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
And then be aware that only those entries of your own manifest are used which are not in the generated by the plugin!
The content of your own manifest file will be merged with the entries created by Maven Archiver. If you specify an entry in your own manifest file it will override the value created by Maven Archiver.
See the apache maven plugin page for entries of the default manifest, and configurable entries. Then you can add further own entries by providing a manifest using <manifestFile>
edit: If you want to use a 1:1 copy you could try to get this done my using the maven assembly plugin, but I think you can you do this with the normal mavne plugins.
I am trying to build jar file of my app based on Maven. So I need to not include external jar library's to my build. I need that my app gives this external dependency in runtime from local maven repository or from local folder, those will contain these external libraries.
I configure my pom file for this dependency like this:
<profiles>
<profile>
<id>compile</id>
<dependencies>
<dependency>
<groupId>groupId</groupId>
<artifactId>some.artifact</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</profile>
and trying to run this jar with this prefix -Pcompile. I am using this answer.
But in the runtime, when I am trying to execute a method, that using this external library, I've got java.lang.NoClassDefFoundError with the name of my class from my external library.
So how I can make a build that will use external jar libraries from local storage?
So i found the solution to store jars outside the final maven build.
I was just need to add this jar to classpath with correct path. For this i add this to pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>${project.build.finalName}.lib/</classpathPrefix>
<mainClass>your.mainClass</mainClass>
</manifest>
<manifestEntries>
<Class-Path>project-0.0.1-SNAPSHOT.lib/some.lib-1.1.jar</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
Basically, we have an ear archive that has multiple dependencies. In those dependencies, we plan on filling the manifest or some properties file with multiple properties:
build timestamp
buildnumber (from CI server)
groupId
artifactId
version
This should already be possible for individual artifacts that are built by our CI server, and this is also not really the problem I'm having.
Now I use maven for building my ear archive, with the maven-ear-plugin. My idea was to just use a groovy script (executed by gmaven-plus) that will read all the jar archives, and fetch the manifest. Then I can rewrite the manifest of the ear archive, or write my own properties file that contains the info I want.
import org.apache.commons.io.FileUtils
import java.util.jar.JarFile
def path = "target/${project.name}-${project.version}"
def artifactDir = new File(path)
def output = new File("$path/META-INF/build-info.properties")
def lines = []
artifactDir.listFiles().each { file->
if (file.isFile() && (file.name.endsWith(".war") || file.name.endsWith(".jar"))) {
def jar = new JarFile(file)
def manifest = jar.manifest
println "processing: $file.name"
println manifest.mainAttributes
println jar.properties
manifest.mainAttributes.keySet().each { attrKey->
def val = manifest.mainAttributes.getValue(attrKey.toString())
lines << "$file.name.$attrKey=$val"
}
}
}
FileUtils.writeLines(output, lines as Collection<?>
)
This script works fine, and will write the build-info.properties file with all the info I'd like to be in there.
This is the plugin configuration:
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>create-manifest</id>
<phase>package</phase>
<goals>
<goal>execute</goal>
</goals>
</execution>
</executions>
<configuration>
<scripts>
<script>file:///${project.basedir}/src/main/gmaven/create-manifest.groovy</script>
</scripts>
</configuration>
</plugin>
Of course, you'll already notice what's wrong with this: the packagephase is too late, prepare-package is too early, because the ear plugin has not yet copied the dependencies I'm scanning.
Conclusion
Well, the obvious thing to do would be to unzip the ear produced, and then add the file manually, then zip it again. But that seems pretty dirty to me, and I was wondering whether there is no cleaner way to do this?
Perhaps by leverageing gradle, or some option of the maven-ear-plugin I have not yet discovered? Or just in general, how would you tackle the specific problem I am facing here?
Why not using the maven possibilities..like the configuration for the archiver which means you can use a configuration like this for the maven-jar-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<index>true</index>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
</manifestEntries>
</archive>
</configuration>
</plugin>
This can also be used for maven-war-plugin, maven-ejb-plugin and for maven-ear-plugin as well...See the docs for maven-ear-plugin see archive entry.
The buildnumber from your CI solution (for example Jenkins) has an env variable BUILD_NUMBER which you can use as well...
Full example how a corporate pom can look like take a look here.
Update:
What i missed is that you can use filtering to create such file. Put a file into src/main/resources with the following content:
groupId=${project.groupId}
artifactId=${project.artifactId}
version=${project.version}
Define the following as part of your pom file:
...
src/main/resources
true
Furthermore this will package the above file into your ear/war/jar file.
Apart from that a file which contains already the above information can be found in earchive META-INF/groupId/artifactId/pom.properties which contains the above. Not the build number and build time...
The build time can be used by using the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestEntries>
<buildTime>${maven.build.timestamp}</buildTime>
<buildNumber>${env.BUILDNUMBER}</buildNumber>
</manifestEntries>
</archive>
</configuration>
</plugin>
${env.BUILDNUMBER} is of course a refererence to bamboos variables which contains such information.
I have been trying for several days now to create an executable jar file for my muli-module maven project. However, when I try to run this jar file I get "Could not find or load main class src.main.java.com.domain.Mainclass" (I have changed the name domain and MainClass for my company's privacy sake)
I have searched for days and none of the obvious tips seem to work.
My project has a main maven project that downloads all of the dependencies (packaging:POM)
and several module projects (Packaging:Jar).
Everything seems to work fine, and all of the files are compiled into class files, but somehow the main class is not being added to the pom.
My Pom File Plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.domain.project.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
The Commands I Use: mvn clean package, then I cd into the target folder and do: java -jar jarfilename.jar
Any tips or help would be most welcomed!
Edit:
My current configuration creates a 2 jar files for every module:
projectname-jar-with-dependencies.jar
projectname.jar
When I navigate to the target folder of the module with my main class, I can successfully run the jar file. However, when I try to run the jar file of my parent maven project (the one with packageing:pom) I still get the same error. Does anyone know why the main jar file cannot find the main class?
Thanks!
You should not have src.main.java as part of the package name of your main class. It's just part of the default maven project folder structure convention. Your configuration should probably read:
<archive>
<manifest>
<mainClass>com.domain.project.MainClass</mainClass>
</manifest>
</archive>
I'm going to necro this post because it is important to have 3 different things set properly:
MainClass.java needs to be in <project_root>/src/main/java/com/domain/project/
Maven assembly plugin needs <mainClass>com.domain.project.MainClass</mainClass>
Your package should be set to com.domain.project
When those three match, Maven should package an executable JAR file.
it seems like you have one of the plugins missing. add the bellow to pom.xml file
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>yourclassnameKt</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
The plugin will add MANIFEST.mf file, which will tell the Java runtime which class to execute.
There is another issue that has the same problem ->
Kotlin + Maven assembling: no main manifest attribute
Reference: https://michaelrice.com/2016/08/hello-world-with-kotlin-and-maven/
I have a bit of a different but similar scenario so I thought I would share. I have a primary maven application packaged into a war through the build (pom.xml packaging configuration). I wanted to add a jar file that is created from one package within our source code, and added into the assembled output along with the webapp war. This allows us to deliver the web application along with a cli tool separately. I didn't want to reconfigure the pom.xml to be multi-module, but just to add a jar as a separate executable within our existing structure. I was banging my head against this for a while.
First, I ended up deleting my entire .m2 directory with maven repositories locally. It appears there may have been an issue for me here, because my ultimate code that worked seems to be the same as what wasn't working originally. I suspect the reasoning for this was I was trying different versions of libraries and was creating conflicts, but who knows. First suggestion I have if you are having issues is delete your .m2 folder and try from scratch.
Also reference #Adam Howell's answer because that is the fundamentals. I created a simplified example project to figure out why nothing was happening and in there I realized i forgot to prefix the folder structure as src/main/java... doh! Of course in my existing project, this was not the case.
And here is my plugin code i inserted in my pom.xml that worked:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.myCompany.app.cli.CLITool</mainClass>
</manifest>
</archive>
<outputDirectory>${project.build.directory}</outputDirectory>
<finalName>our-cli</finalName>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
I am pretty sure you can change the phase you want this done in, I figured earlier on in compile made since to ensure it was available for packaging later. I'm not very experienced with Maven though, so note that this may not be semantically in-line with Maven conventions.
And it worked! Not sure why this took me hours to work out although it did. This I just updated my bin.xml to include the jar file in my assembled deliverable, and Voilah! I have a jar executable separate from my webapp that I can use as a command-line interface tool.
Is there a way to pack the dependencies of a maven ejb project in with the final jar?
I typically use a separate ear project and include the ejb as a dependency - it will fill out the lib folder automatically this way. However, this seems a bit wasteful - to have a project just to build the ear.
Right now I have:
<artifactId>projectname</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>ejb</packaging>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
<ejbVersion>3.1</ejbVersion>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- without this, the datetime stamp unique id's will be appended to classpath items -->
<!-- see: http://maven.apache.org/shared/maven-archiver/examples/classpath.html#Snapshot -->
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
</configuration>
</plugin>
Do I need to set the packaging type to ear? Can I include transitive dependencies in a standalone ejb jar? If I set it to ear, how do I config the ear plugin?
Thanks in advance!
The Maven Shade Plugin can package dependencies in with the JAR. It will extract the classes/resources from all the project's dependencies on package them in with the final JAR.
This should be enough to package all your dependencies:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
There are disadvantages to doing this, however.
Multiple resources with the same name in different JARs can cause problems (e.g. /META-INF/services/...). You can use Shade's resource transformers, but it can get messy.
Not as easy to track what JARs are dependencies in your project once deployed (you'd have to refer back to the POM instead of just looking at the EAR).
Unless you have good reason not to, I'd recommend you stick with building an EAR.
I don't think there is a direct way to do this. Instead, what can be done is to create it as a module project with an ear and an ejb module. It isn't exactly what I wanted, but it works and is better than separate projects.