If I wanted to create a jar file without META-INF nonsense using jar utility I can pass the -M switch, which will:
-M do not create a manifest file for the entries
Note that this is a feature of the jar utility. If I use it, I will get a jar without the META-INF folder and included MANIFEST, basically just an archive of type jar with whatever files/directories I put in it.
How do I do this with the maven-jar-plugin? I need to do this to conform to another process. (They expect a jar with very specific file/folder layout and I cannot have a META-INF folder at the root of the jar file.)
I've got the configuration to create the jar file just right and I don't want to mess with another plugin...
In maven-jar-plugin there is no option to disable creation of manifest folder, but you can disable the maven descriptor directory like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<addClasspath>false</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
If absolutely you want to delete the META-INF folder you can use maven-shade-plugin like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
You can use maven-shade-plugin to achieve the desired effect:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>${project.groupId}:${project.artifactId}</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
The configuration filters out the META-INF directory and includes only the current project so that dependencies are not attached.
Related
I have a single maven project that has multiple folders in src/main/resources, I want to generate two Jars, one include src/main/resources/folder1/all properties and the other include src/main/resources/folder2/all properties.
Is their a way to achive this ? If not, what is the simplest way to achive my goal?
If I understood your problem correctly then you can use "Maven Assembly plugin" and "The Assembly Descriptor" in the following way:
first of all, you can not use a profile if you want to build 2 jar files simultaneously.
So, my suggestion is to exclude your config files from your jar then use Maven Assembly plugin to create a different zip file with these folders.
for example, in your case you should have 2 file descriptors like the following:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>folder1</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/java/descriptors/folder1.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
and folder1.xml contains:
<assembly>
<id>folder1</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>
target/${project.artifactId}-${project.version}-yourJar.jar
</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/resources/folder1</directory>
<includes>
<include>*</include>
</includes>
<outputDirectory>/config</outputDirectory>
</fileSet>
</fileSets>
</assembly>
for "folder2" you can do it in the same way.
also for exclude some config files from the jar you can use this plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>package.path.to.your.main.class.MainClass</mainClass>
</manifest>
<manifestEntries>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
Using maven-resources-plugin as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
From Introduction to Build Profiles
Profiles can be activated in the Maven settings, via the section. This section takes a list of elements, each containing a profile-id inside.
<settings>
...
<activeProfiles>
<activeProfile>profile-1</activeProfile>
</activeProfiles>
...
</settings>
Profiles listed in the tag would be activated by default every time a project use it.
Profiles can be automatically triggered based on the detected state of the build environment. These triggers are specified via an section in the profile itself. Currently, this detection is limited to prefix-matching of the JDK version, the presence of a system property or the value of a system property.
This allows to create a different package content based on the target environment.
I have these folders in my project structure
/src/main/java
/src/main/resources
In the "resources" folder I have 2 files: "config.properties" and "logging.properties".
And I have the following "" in my pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>myapp.Main</mainClass>
</manifest>
</archive>
<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>
</plugins>
</build>
When I run "mvn clean package", it does generate the "target" folder with the jar and the "classes" folder containg the properties file as mentioned above.
To read one of the properties files (after clicking on a Button), I'm using the following code:
Properties prop = new Properties();
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties"));
String logFolder = prop.getProperty("myApp.property");
//Do something with 'logFolder'
It runs OK.
But if I change the "myApp.property" in "logging.properties" file, the change doesn't affect the "logFolder" value.
What must I do to be able to dinamically change the property value and make my application read the new value WITHOUT RECOMPILING THE PROJECT?
Thank you.
You can invoke respective plugins manually:
mvn resources:resources maven-assembly-plugin:single
Though this is not the best option anyway. It's better to eliminate re-packaging all together for local deploys:
Just start the app in IDE instead of building a JAR. IDE will detect changes in the configs.
And in general allow overriding your variables with either env vars or system variables. So after reading the file also check if the values are overriden and use those.
For remote deploys we usually don't keep configuration files in JAR (you don't want to keep PRD passwords in there, right?). So deploying to remote envs should use config files from restricted sources. This means that the app needs to be able to read configs that are not inside JAR.
Here's what I added to my pom file so Maven loads the resources into the jar at the root level.
<resources>
<resource>
<directory>src/my-resources</directory>
<includes>
<include>**/*.txt</include>
<include>**/*.jpg</include>
</includes>
</resource>
</resources>
</build>
Notice how my folder, called my-resources, is not placed under main, it's placed under src. Of course, without telling Maven about your resource in the pom it won't do anything for you.
I didn't check your code, but there's how to tell Maven to pack your resources into your jar for you. And at a glance at your code, when working from inside a jar, you need to prefix your filename with a '/' because it's now using a relative path, not an absolute path.
getResourceAsStream("logging.properties") works outside a jar.
getResourceAsStream("/logging.properties") is what you need inside a jar.
I managed to solve this issue.
The other answers are correct. The real problem (I think) is with this "maven-assembly-plugin" that I was using to build.
For some reason, it does not read my properties files after build, maybe I was doing something wrong with it.
So, I changed my <build> script in my pom.xml to the following:
<build>
<finalName>myapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>logs</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>myApp.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/logs</include>
<include>**/*.properties</include>
<include>**/*.gif</include>
</includes>
</resource>
</resources>
</build>
In short: I replaced the "maven-assembly-plugin" with "maven-dependency-plugin" (I'm using an Oracle DB in this project), "maven-resources-plugin" (copying all of my resources to "/target" folder after build) and the "maven-jar-plugin" setting the "Class-path" property to ".".
In the resources in the profile folder there is a configuration file, depending on the profile it should be taken and put in the resource root
Actually, what I encountered
He puts it in the project itself, and not in the original jar
When the second time you collect this file already comes
So that the folder itself in the jar does not fall
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<executions>
<execution>
<id>copy-properties</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/profile/${profile.dir}</directory>
<includes>
<include>server.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>${maven-ejb-plugin.version}</version>
<configuration>
<filterDeploymentDescriptor>true</filterDeploymentDescriptor>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<ejbVersion>3.0</ejbVersion>
</configuration>
</plugin>
</plugins>
Tell me where I was wrong?
In which plugin to configure maven-ejb-plugin or maven-resources-plugin
I have src/main/recoursces/profile/
serverA/server.properties
serverB/server.properties
serverC/server.properties
I want jar
- It did not have a folder profile
- and have one server.properties
I'm not sure if I understand your question. I believe the resources phase package is not correct, it should be on a previous one like process-resources.
Here you have the Maven Lifecycle Reference
process-resources: copy and process the resources into the destination directory, ready for packaging.
package: take the compiled code and package it in its distributable format, such as a JAR.
I am creating an uber jar i.e. jar with dependencies for my project. I have a bunch of properties files that the project uses. I want to be able to change these properties files before running my project so i want them to be outside of the jar. Here is the relevant sections of my pom
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<artifactSet>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.json</exclude>
</excludes>
</artifactSet>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>path.to.main.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.json</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
so essentially, I want to create a folder ${basedir}/target/conf and copy all the .properties and .json files to it. Also, here is how I am reading the files
InputStream in = this.getClass().getClassLoader().getResourceAsStream("filename.properties");
I am facing a couple of problems
When i do mvn clean install, i still see the all the .properties and .json files in the classes folder. Shouldn't they have been excluded?
The conf folder is created with all of the files, but when I run the jar adn try to change the properties, the changes are not picked up. How can i ensure that the conf folder is being added to the classpath?
I want to be able to load the .properties and .json files from the src/main/resources folder while i am developing so i dont want to put them in a separate folder. Is this possible?
I was facing the same issue where Uber jar is not reading the external configuration file.
I tried below configuration and it worked like charm. Refer below configuration it may help someone having the issue with uber jar not reading extenarl files.
I am not sure if this is the best way but haven't found any soultion online :)
I have included the resources using IncludeResourceTransformer.
Using filter removed the properties file from uber jar.
In classpath /conf reading the properties from external folder.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions> <!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
add Main-Class to manifest file
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>JobName</Main-Class>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>src/main/resources/config.properties</resource>
<file>${project.basedir}/src/main/resources/config.properties</file>
</transformer>
</transformers>
<finalName>FinalJarName</finalName>
<filters>
<filter>
<artifact>groupId:artifactId</artifact>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
good luck.
I am trying to test if I can jar 3rd party dependencies into my jar, SSH the jar over to a remote machine, and then run a map reduce job.
Process:
With my project, I run mvn clean package and that produces the files my-appy-1.0-SNAPSHOT.jar and original-my-appy-1.0-SNAPSHOT.jar. I scp the first file over to my remote machine and run the command:
hadoop jar hadoop my-appy-1.0-SNAPSHOT.jar /user/bli1/wordcount/input /user/bli1/wordcount/output
I also tried:
hadoop my-appy-1.0-SNAPSHOT.jar WordCount /user/bli1/wordcount/input /user/bli1/wordcount/output
I'm not sure why I am getting this error:
Error: Could not find or load main class my-appy-1.0-SNAPSHOT.jar
pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<artifactSet>
<excludes>
<exclude>org.hamcrest:*</exclude>
<exclude>org.mockito:*</exclude>
<exclude>org.objenesis:*</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/LICENSE</exclude>
<exclude>META-INF/license</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.mycompany.app.WordCount</Main-Class>
<Build-Number>1</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Open your *.jar file and check it's MANIFEST.mf file. It should contain the "Main-Class" row with your class with "public static main()" method. If there is no "Main-Class" add it yourself
This link will help you do this: https://docs.oracle.com/javase/tutorial/deployment/jar/appman.html
you need to give full path to main class including package name.
hadoop my-appy-1.0-SNAPSHOT.jar com.mycompany.app.WordCount /user/bli1/wordcount/input /user/bli1/wordcount/output
The command you run through jar file is as below:
hadoop jar jar_filename.jar package_name.class_name HDFS_inputfile_name HDFS_output_directory
Your command should be
hadoop jar my-appy-1.0-SNAPSHOT.jar com.mycompany.app.WordCount /user/bli1/wordcount/input /user/bli1/wordcount/output