Is it possible to combine two jar files such that in an applet tag I can simply do something like
archive="jarjar.jar/jar1.jar"... ...archive="jarjar.jar/jar2.jar"... instead of
archive="jar1.jar"... ...archive="jar2.jar"...
I need to only have one jar file so putting two jar files in a folder will not help me.
Sure, just extract the two jar files and recreate a new one
$ mkdir tmp
$ (cd tmp; unzip -uo ../jar1.jar)
$ (cd tmp; unzip -uo ../jar2.jar)
$ jar -cvf combined.jar -C tmp .
The stuff with tmp ensures that the two existing jars are extracted into a clean directory and then the new one made from that.
Be aware that you may also need to merge any manifest.mf files contained therein, and if there are any also include the '-m' option in that file command.
Use zipgroupfileset with the Ant Zip task
<zip destfile="out.jar">
<zipgroupfileset dir="lib" includes="*.jar"/>
</zip>
Might help you.
If you are using gradle, just add the following to build.gradle. No plugins required. If you need special options, then go with Fatjar plugin, as initialZero suggests.
task superSimpleJar(type: Jar) {
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
For Android project, add this to app/build.gradle and run "gradlew superSimpleJar". Find jar in build/libs/app-all.jar
task superSimpleJar(type: Jar) {
baseName = project.name + '-all'
from {
configurations.compile.findAll {
it.getName() != 'android.jar'
}.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project name="zip-test" default="zip" basedir=".">
<target name="zip">
<zip destfile="out.jar">
<zipgroupfileset dir="." includes="*.jar"/>
</zip>
</target>
</project>
save this code in build.xml file and keep it in same folder where all the jar files to be combined are kept. Open cmd, give path of folder and run command : ant zip.
It will generate out.jar which is combination of all jars.
Just unzip both jar files, then zip the results into one zip file, and rename this to jar again.
But as adarshr said: Better use the jar command for that.
Extract both jars and create a new one works. (Use jar commands shown above).
One caveat about manifest file is that you want to extract the jar whose manifest file you want to retain in the last.
I know it's an old question and I just wanted to add my two cents (no permission to comment yet, so creating a new answer).
I do see the value in sumanth.donthula's answer as the problem for all of us merging jars will be how to deal with the manifest files. In my case I wanted to merge some library files (mainly generated web service client code) into the jar of an application written by me. It was OK to replace the manifests with the one of my own jar.
The simplest way of doing this is taking care of the order in which you unzip the original files (as Alnitak and sumanth.donthula noted).
I wanted to use the zip ant task (thank you, ykombinator, for the idea). It turned out that the only way of controlling the order of compressing/packaging is renaming the files. See my ant target below.
The output directory in my example is called codemodule.dir (I created a FileNet code module). The rest of the names are self-explaining. The important step is renaming the application jar to 0_... to be the 1st in order. This way its manifest will be retained as the duplicate attribute of the zip ant task is set to preserve.
<target name="merge_jars">
<delete dir="${codemodule.dir}" quiet="true" />
<mkdir dir="${codemodule.dir}" />
<copy todir="${codemodule.dir}">
<fileset dir="${lib.dir}" includes="*.jar"/>
<fileset dir="${basedir}" includes="${app-name}.jar"/>
</copy>
<move file="${codemodule.dir}/${app-name}.jar" tofile="${codemodule.dir}/0_${app-name}.jar"/>
<zip destfile="${codemodule.dir}/${app-name}-fat.jar" duplicate="preserve">
<zipgroupfileset dir="${codemodule.dir}">
<include name="*.jar"/>
</zipgroupfileset>
</zip>
Related
I have some code that I revised.
When I try to just run Ant in the directory it fails with missing classes. I can specify the location to the existing classes by using the -lib option to ant. The compile then works fine, however dist ZIP file that is created appears to have missing libraries, as when I try to run it, I see errors relating to missing classes which are the classes that I specified with the -lib option, so this is probably due to the way I have used the -lib option.
How can I force the regular Ant command to include the additional classes specified with the -lib command?
You can write a target that will copy your lib directory/files in your zip file.
Let's say create a temp dir then copy your files then execute target for copying lib directory and then zip temp dir.
<target name="copyLib">
<copy todir="${temp.dir}">
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</copy>
</target>
Update paths and call this target into your create zip target.
Compiler task could look like this:
<javac srcdir="${base}/src"
destdir="${base}/classes"
classpath="${base}/lib">
</javac>
And the zip task could look like this:
<zip
destfile="${base}/dist.jar"
basedir="${base}/classes"
includes="..."
excludes="...">
</zip>
So sources are compiled in classes and zipped in a jar, but libraries used for compile are not included in the jar, they are runtime dependencies.
I would suggest that you declare your paths at the top of your ANT scripts as follows, using a fileset.
<path id="build.path">
<fileset dir="lib" includes="*.jar"/>
</path>
Less error prone compared to forcing users to specify the correct "-lib" parameter.
Finally the same fileset can then be used to include the same jars inside the zip file you're creating:
<zip destfile="${dist.dir}/mycode.zip">
..
..
<fileset dir="lib" includes="*.jar"/>
</zip>
I have to copy a file if a property is set in ant target, but I always get an error for this code:
<condition property="component.is.x">
<equals arg1="${COMPONENT_ID}" arg2="x" />
</condition>
<target name="copyschemaparamsfile" if="sql.file.present" >
<if>
<equals arg1="${component.is.x}" arg2="true" />
<then>
<copy file="${in.root}/schema/${COMPONENT_ID}-schema.sql"
tofile="${tmp.dir}/${COMPONENT_ID}/x/schema/schema.sql"
failonerror="false" />
</then>
<else>
<copy file="${inf.root}/schema/${COMPONENT_ID}-schema.sql"
tofile="${tmp.dir}/${COMPONENT_ID}/${COMPONENT_ID}/schema/schema.sql" failonerror="false" />
</else>
</if>
</target>
Error is:
Ant could not find the task or a class this task relies upon.
This is common and has a number of causes; the usual
solutions are to read the manual pages then download and
install needed JAR files, or fix the build file:
- You have misspelt 'if'.
Fix: check your spelling.
- The task needs an external JAR file to execute
and this is not found at the right place in the classpath.
Fix: check the documentation for dependencies.
Fix: declare the task.
- The task is an Ant optional task and the JAR file and/or libraries
implementing the functionality were not found at the time you
yourself built your installation of Ant from the Ant sources.
Fix: Look in the ANT_HOME/lib for the 'ant-' JAR corresponding to the
task and make sure it contains more than merely a META-INF/MANIFEST.MF.
If all it contains is the manifest, then rebuild Ant with the needed
libraries present in ${ant.home}/lib/optional/ , or alternatively,
download a pre-built release version from apache.org
- The build file was written for a later version of Ant
Fix: upgrade to at least the latest release version of Ant
- The task is not an Ant core or optional task
and needs to be declared using <taskdef>.
- You are attempting to use a task defined using
<presetdef> or <macrodef> but have spelt wrong or not
defined it at the point of use
Remember that for JAR files to be visible to Ant tasks implemented
in ANT_HOME/lib, the files must be in the same directory or on the
classpath
I am always getting above error when I execute. Can someone please suggest how to check for a parameter and copy from one directory to other within an ant target?
Ant <if/> is part of Ant-Contrib. To use, follow the directions on the Ant-Contrib Tasks installation page:
(1) Copy ant-contrib-0.3.jar to the lib directory of your Ant
installation. If you want to use one of the tasks in your own project,
add the lines
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
to your build file.
(2) Keep ant-contrib-0.3.jar in a separate location. You now have to
tell Ant explicitly where to find it (say in /usr/share/java/lib):
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="/usr/share/java/lib/ant-contrib-0.3.jar"/>
</classpath>
</taskdef>
I'm trying to create a jar from my eclipse and in order to be able to use the external .jars, I'm using this manifest with multiple .jars in the classpath:
Manifest-Version: 1.0
Sealed: true
Main-Class: src.BatchTester
Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstream/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/antlr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:/Tools/Jdbc/lib/sqljdbc4.jar
Obviously if I don't put the libraries in the classpath the following error appears:
java.lang.NoClassDefFoundError: com/thoughtworks/xstream/XStream
But when I put them in the classpath the error changes to:
java.lang.NoClassDefFoundError: src/BatchTester
So it seemps that it can't found my main class. I've tryed with several possibilities in the classpath, like adding or removing . to the classpath, but can't make it work.
Any idea of how can I solve this???
Thanks for your time and effort,
PS: After creating the .jar the classpath in the manifest inside looks like:
Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstr
eam/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/ant
lr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:
/Tools/Jdbc/lib/sqljdbc4.jar
with new lines and spaces, but even after changing it to the "right" format, I got the same problems.
PS2: I know that with some plugins like Fat-Jar you can make it work, but I don't want to insert more data than needed in my .jar
Finally I've copied all the libs into the /lib folder and add them into the .jar with an ant target since seems to be OK with the IT guys (because it is a small application).
Here is the ant(in case is useful for someone):
<?xml version="1.0" encoding="UTF-8"?>
<project name="BatchTester" default="compile" basedir=".">
<property name="external" value="lib/external-libs.jar"/>
<target name="compile">
<javac srcdir="jav"
source="1.6"
/>
<echo>Creating jar File</echo>
<!--create a new .jar with all the external jars in /lib-->
<jar jarfile="${external}">
<zipgroupfileset dir="lib/">
<include name="**/*.jar"/>
</zipgroupfileset>
</jar>
<!--<sleep seconds="1"/>-->
<!--create .jar file-->
<jar jarfile="BatchTester.jar" index="true" filesetmanifest="mergewithoutmain">
<fileset dir=".">
<include name="**/jav/**/*.class"/>
<exclude name="**/jav/**/*.java"/>
</fileset>
<zipfileset src="${external}">
<exclude name="META-INF/*.SF"/>
</zipfileset>
<manifest>
<attribute name="Main-Class" value="jav.BatchTester"/>
</manifest>
</jar>
<!--delete previously created extern .jar-->
<delete file="${external}"/>
</target>
</project>
Sorry If my questions sounds obvious for you.
*Launch Command *
In order to exclude any doubt, didn't you tried to launch your jar with this kind of command ?
java -jar myJar.jar -cp ./lib
If you use classpath option, you probably didn't ;). Option --classpath (or -cp) and -jar can't be uses together.
Prefer the use of relative path too, like ./lib instead of P:/Tools/... But, anyway, that won't solve your problem.
*Package Location *
As brimborium said, what is you real package ? src sounds very strange. We suspect an error around this.
In your BatchTester class, what have you written for package directive ? Nothing (i.e default package which isnot recommanded ?)?
Does you class begin with (get rid off comments)
public class BatchTester {
In that case, for sure, src should not be mentionned.
Here an example of manifest which work for me.
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: jrRevy
Build-Jdk: 1.6.0_31
Main-Class: com.sopragroup.training.dojo1.MainSwingApp
Class-Path: dojo1-0.5.0-SNAPSHOT-lib/spring-core-3.1.1.RELEASE.jar doj
o1-0.5.0-SNAPSHOT-lib/spring-asm-3.1.1.RELEASE.jar [blablabla]
with the following execution structure
/
|
+ --dojo1-0.5.0-SNAPSHOT.jar
|
+ --dojo1-0.5.0-SNAPSHOT-lib/
|
+ --spring-core-3.1.1.RELEASE.jar
Obviously, I'm using maven for build my app, but the main idea is in.
The manifest doesn't allow absolute paths in the Class-Path: tag. You have two alternatives:
Use relative paths as you already mention in your own answer
Use absolute paths via file protocol. This has been answered elsewhere too and it works absolute versus relative path names in jar manifest
Class-Path: file:///P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar
In addition, you should not edit the manifest.mf manually without being aware of several limitations:
line maximum length must not exceed 72 characters, and after breaking one line you must insert an space in the first column.
There must be a carriage return after the last line otherwise, the file can't be parsed correctly
How does one go about creating two Jars from one project source folder? Is that possible, or must I create another project? My project uses Ant right now to generate one Jar. For example, say I want to split up the class files like this:
Jar 1:
com.myproject.Foo
com.myproject.Bar
Jar 2:
com.myproject.FooBar
com.myproject.BarFoo
com.myproject.FooBarFoo
...
See http://ant.apache.org/manual/Tasks/jar.html. You just have to use filesets or includes/excludes inside your jar task to include only the files you want in each jar:
<target name="makeJars">
<jar destfile="jar1.jar"
basedir="classes"
includes="com/myproject/Foo.class, com/myproject/Bar.class"/>
<jar destfile="jar2.jar"
basedir="classes"
includes="com/myproject/FooBar.class, com/myproject/BarFoo.class, com/myproject/FooBarFoo.class" />
</target>
I am currently doing this:
<jar update="yes"
jarfile="${pwd}/dist/${release}_installer.jar">
<zipfileset src="${pwd}/dist/app.jar" includes="com/izforge/izpack/panels/**"/>
<zipfileset src="${pwd}/dist/app.jar" includes="com/xyz/img/logo.png"/>
</jar>
My existing installer JAR gets updated to include the files as needed, extracted from the app JAR.
So far, so good.
However, I want to modify the behaviour such that the path of the image file is different than what is being copied from:
Currently:
com/izforge/izpack/panels/MyIzPanel.class
com/xyz/img/logo.png
What I want:
com/izforge/izpack/panels/MyIzPanel.class
blah/img/logo.png
So I need to copy the files, but use <zipfileset> and <jar> in such a way that I can modify the directory structure.
Is there a way to do this, apart from unzipping the entire contents copying file and then zipping it back up again?
EDIT:
Link to earlier related question: ant task to remove files from a jar
You can use the fullpath attribute:
<zipfileset src="${pwd}/dist/app.jar"
includes="com/xyz/img/logo.png" fullpath="blah/img/logo.img"/>
If you need to copy several files you may want to have a look at the prefix attribute, e.g.:
<zipfileset src="${pwd}/dist/app.jar"
includes="**/*.png" prefix="blah/img"/>
In order to modify the directory structure within the archive on the fly you can use the task in combination with <mappedresources>, eg:
<jar file="target.jar" update="true">
<mappedresources>
<zipfileset src="source.jar">
<include name="com/xyz/img/*.png"/>
</zipfileset>
<mapper type="glob" from="com/xyz/img/*.png" to="bla/img/*.png" />
</mappedresources>
</jar>
You should probably look into zipgroupfileset as explained here.