Ant: Split Source Directory into Two Jars - java

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>

Related

Exclude Jar from Ant Build using zipgroupfileset

I have created a Jar Project which contains Filter.
I need to use servlet-api.jar when I compile the Filter code.
But when I want to use the Jar in another application, I want to build the jar in such a way that it will exclude servlet-api.jar.
I am using Apache Ant with NetBeans 8:
I have added below code in build.xml.
<target name="-post-jar">
<jar destfile="dist/MyJar.jar">
<zipfileset src="dist/MyJarAsLibrary.jar"/>
<zipgroupfileset dir="dist/lib/." excludes="javax/*"/>
</jar>
</target>
I have used Apache Ant zipgroupfileset.
But I searched on google I found the excludes for files.
I tried with excluding the servlet packages as javax/*, but it did not work.
No Idea how to exclude specific packages.
I found few excludes with zipfileset, but I need to use zipgroupfileset and exclude the javax.servelt.* packages.
The excludes attribute of zipgroupfileset is used to select the archives to pick entries from, not to filter the contents of the archives. zipgroupfileset always contains everything included inside the matched archives.
The simple solution if you know which archive contains the servlet classes is to exclude it from the zipgroupfileset and add an explicit zipfileset.
If you don't know the archive, you can mimic zipgroupfileset using the archives resource collection and wrap that into a restrict container. Something like
<restrict>
<archives>
<zips>
<fileset dir="dist/lib/"/>
</zips>
</archives>
<not>
<name name="javax/servlet/*"/>
</not>
</restrict>

Ant zip change base dir to zip at different level

I have an Ant zip task that looks like this:
<zip basedir="${workspace.dir}"
destfile="${build.output.dir}/test.zip"
includes="${eLibrary}/bin/com/**,
${Common}
excludes="${eLibrary}/lib,
${eLibrary}/src"
>
</zip>
The eLibrary folder has a structure similar to:
`--bin
`--com
`--lib
`--src
I'd like to have the zip file look like this:
`--eLibrary
`--com
`--Common
When the zip is created though it has the following structure:
`--eLibrary
`--bin
`--com
`--Common
I've tried various types of include statements, but they all include the bin folder:
includes="${eLibrary}/bin/**
includes="${eLibrary}/bin/com/**
includes="${eLibrary}/bin
includes="${eLibrary}/bin/com
Changing the basedir won't work because I also need the Common folder included. Any help would be appreciated. Thanks.
You can check the zip task documentation for examples on how to achieve this. The below snippet uses a zipfileset nested element which maps the included entries to the directories inside the archive.
<zip destfile="${build.output.dir}/test.zip">
<zipfileset dir="${eLibrary}/bin/com" prefix="${eLibrary}/com"/>
<zipfileset dir="${Common}" prefix="${Common}"/>
</zip>

How to include all dependent Jars within a single non-executable jar?

I am stuck in a very common problem.
I am plugging my jar (which has many dependencies on third party vendor) into an application server lib directory. If I just copy my jar along with its dependencies into server lib then server classpath becomes to long and hence server is not able to work. Therefore I want to package this Jar with all its dependencies in a single jar so that server's classpath doesn't become too long. I found on various forums that there is a utility to do this i.e. OneJar. But this utility works on executable jar. In my case, my final jar will not be executable.
Also I tried ZIPFileSetGroup utility provided by ANT but that is causing security issues with Manifest file.
Can you please help me in resolving this issue?
Thanks!
If you use Maven to build, you can use the maven dependency plugin and use the copy-dependency task. It will copy all dependencies into your jar file when it creates it.
If you manually add the jars to your jar file, then you need to make sure your jar file has a Manifest.mf file in it and specify the main class and classpath inside of that.
Manifest-Version: 1.0
Main-Class: com.mypackage.MainClass
Class-Path: my.jar log4j.jar
Another option may be to build an .ear file, that is usually how you see enterprise apps or a .war file for web apps when they package specific jar files with them. It sounds like you are using a server, so one of those formats may be a better fit for you.
Using zipgroupfileset in the jar task in ANT is the easiest approach.
<jar destfile="MyApplication.jar" filesetmanifest="mergewithoutmain">
<zipgroupfileset dir="lib" includes="*.jar" />
<!-- other options -->
<manifest>
<attribute name="Main-Class" value="Main.MainClass" />
</manifest>
</jar>
Note the filesetmanifest flag set to mergewithoutmain merges everything but the Main section of the manifests.
Signed jars are causing the SecurityException which need to be handled manually. If any classes associated with signed jars verify the signature on the jar as a whole then those will fail at runtime. Digest signatures against a particular file will be added to the manifest without a problem. Since problem is your classpath getting too large you may not be able to bundle all the jars into a single jar but merge most of them making the CLASSPATH manageable.
There is also : http://code.google.com/p/jarjar/
Create target directory with all dependent jars. Next move 10 jars into a temp directory and keep moving the jars in batches of 10 and each time try to create the single jar from that group. When you get the security exception you can isolate which one is causing the problem. Try divide-and-conquer approach. If you have 300 jars then only have to do this 30 times.
When you say
child process picks up classpath from server/lib directory
is this a process that is under your control? If the parent process were to specify the classpath just as
server/lib/*
(i.e. a literal *) then the target java process will enumerate the jar files in the lib directory itself - they do not all need to be named on the classpath.
But if the parent process is explicitly enumerating server/lib/*.jar to build the -cp value then you could take advantage of the fact that the Class-Path in a JAR manifest takes effect even if a JAR is not "executable". You could use a stanza like this to create a manifest-only JAR file
<!-- location of your 300 dependency JAR files, file1.jar ... file300.jar -->
<property name="lib.dir" location="lib" />
<fileset id="dependencies" dir="${lib.dir}" includes="*.jar" />
<pathconvert property="manifest.classpath" dirsep="/" pathsep=" "
refid="dependencies">
<map from="${lib.dir}" to="myapp" />
</pathconvert>
<jar destfile="myapp-manifest.jar">
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
</jar>
This will produce a JAR file named myapp-manifest.jar whose manifest contains
Class-Path: myapp/file1.jar myapp/file2.jar ... myapp/file300.jar
You put this file into server/lib and the 300 dependencies into a new directory server/lib/myapp. Now the generated -cp will include just one file (myapp-manifest.jar) but the resulting java process will have all the 300 myapp JAR files available to it.

JAR classpath and external jars

I actualy have 2 problems
I use eclipse -> export project to generate a jar file for my simple desktop (GUI) program
It generates a jar file and an ant script.
first problem:
the generated jar works fine when double-clicked.
When I use the generated ant script to generate the jar
by myself, it doesn't work.
What can be wrong with a target like this (assuming that all dependencies are met)
<target name="create_run_jar">
<jar destfile="G:/dev/myproj/myproj.jar">
<manifest>
<attribute name="Main-Class" value="view.myproj"/>
<attribute name="Class-Path" value=". myproj_lib/grouplayout.jar"/>
</manifest>
<fileset dir="G:/dev/myproj/bin"/>
</jar>
<delete dir="G:/dev/myproj/myproj_lib"/>
<mkdir dir="G:/dev/myproj/myproj_lib"/>
<copy file="G:/dev/.metadata/.plugins/org.dyno.visual.swing/layoutext/grouplayout.jar" todir="G:/dev/myproj/myproj"/>
</target>
//nevemind
//Second problem:
//when I double click on the auto-generated jar file the program launches and works fine.
//when I do java myjar from the command-line I get main class not found exception..
//weird huh?
I suggest that you take the JAR files generated the two ways, use the jar command to expand them into temporary directories, and then use diff in recursive mode to compare them.
However, I suspect that #Pace has put his finger on the problem; i.e. that you are using relative paths in the Class-Path manifest entry and this is liable to cause problems.
java -jar <jar name> is the proper way to execute a jar.
The ant target is creating a manifest with a classpath attribute. If you look at those paths you'll notice that they are relative to the current directory. When you execute java -jar from the command line are you in the...
G:/dev/myproj
...directory?

How to combine two Jar files

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>

Categories

Resources