I'm using Apache Ant to compile, jar and run a java project for school. I've run into a problem that I don't know how to include a single .txt file into my .jar, and then reference it as well in my java code.
Here is my compile and jar command in my build.xml.
<target name="compile">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes"/>
</target>
<target name="jar">
<mkdir dir="build/jar"/>
<jar destfile="build/jar/BinaryTree.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="cs3345.MainLauncher"/>
</manifest>
</jar>
</target>
What command do I use to include a .txt file into my jar. I've seen a couple Stack Overflow questions about it already, notably
adding non-code resources to jar file using Ant
How can I include data text files in a jar using Ant?
But none of them really explained how to include a file. They just had commands that didn't really make sense to me. I've tried,
<jar destfile="build/jar/BinaryTree.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="cs3345.MainLauncher"/>
</manifest>
<fileset dir="src/resources" />
</jar>
But that didn't seem to help because I just don't understand Ant, I couldn't find documentation for it that actually explained why you do different things in ant.
My .txt file is in, src/resources.
The <jar> task tasks multiple filesets:
<jar destfile="build/jar/BinaryTree.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="cs3345.MainLauncher"/>
</manifest>
<fileset dir="src/resources" />
</jar>
The <manifest> task is a sub entity. It's very much like the <manifest> task. In your jar is a file called META-INF/MANIFEST.MF and this is adding another attribute to that jar. This particular attribute tells the Jar what is the main class which should launch when the jar is exeuted.
The <fileset dir="src/resources"/> is adding all the files that are found in theresources` directory. What if you only want to add a particular file? You can use selectors. For example:
<jar destfile="build/jar/BinaryTree.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="cs3345.MainLauncher"/>
</manifest>
<fileset dir="src/resources">
<include name="foo.txt"/>
</fileset>
</jar>
This time I'm not adding the entire resources directory tree. I'm just adding a single file called foo.txt into my jar file.
Use <copy>:
<target name="copy" depends="blablabla" description="Copies additional files">
<echo>Start Copying Files</echo>
<copy file="./src/resources/a.txt" overwrite="true" todir="build/classes/"/>
<echo>End Copying Files</echo>
</target>
As a side note
If we want to include some files under src folder, we can write under target something like:
There is nothing in the documentation that says, "you can only add .class files". The fileset tag should work. Perhaps it's putting the file in a place you're not looking. Run in verbose mode to figure out what it's doing with your .txt file. To control the destination, you should use the zipfileset tag.
But that didn't seem to help. My .txt file is in, src/resources.
You're going to have to elaborate on that. How didn't it help? Is the problem that the file was nested under the zip or didn't go in there or you got an error?
Related
Using ant 1.5
I am trying to create a jar file with files compiled under product directory that can constantly change the build name
/target
|---myapp-1.3.5-SNAPSHOT
|--- WEB-INF
|---classes
|---i18n
It's kind of picky but I have to make a jar file that still keep the web structure
|---myapp-utility.jar
|--- WEB-INF
|---classes
|---i18n
That means I have to put wild card to identify the directory with build and snapshot
<jar destfile="myapp-utility.jar">
<manifest>
....
</manifest>
<fileset dir="myapp-**/"/>
</jar>
and it doesn't work, wild card is not recognized. So what is the alternative?
You can use pathconvert to analyze the wildcard specification:
<pathconvert property="myapp.dir">
<dirset dir="target" includes="myapp-*"/>
</pathconvert>
<jar destfile="myapp-utility.jar">
<manifest>
<!-- .... -->
</manifest>
<fileset dir="${myapp.dir}"/>
</jar>
Ant 1.5 is a very old version of Ant. If you can use at least Ant 1.8.2 (released in 2010), you can use the following...
<jar destfile="myapp-utility.jar">
<mappedresources>
<fileset dir="target">
<include name="myapp-*/**"/>
</fileset>
<cutdirsmapper dirs="1"/>
</mappedresources>
</jar>
The <mappedresources> resource collection wraps the <fileset> element and then applies a mapper to the results.
It's true that the dir of <fileset> can't handle wildcards. Luckily, <include> can handle wildcards. So, the above puts the wildcard test into <include>. The ** ensures all files under myapp-* are matched.
Finally, <cutdirsmapper> removes the myapp-1.3.5-SNAPSHOT/ part from each file.
I have defined a jar task using ant build.xml. I need to bundle all the dependencies into my jar. I don't understant why ant extracts the jars and includes both .jars and .class files into my jar. It unnecessarily increases the size of my jar file. Here is my jar task.
<jar destfile="build/main/ERS2SupportingUtilities.jar">
<fileset dir="target/classes">
<exclude name="*.sh"/>
</fileset>
<restrict>
<name name="**/*.class"/>
<archives>
<zips>
<fileset dir="./src/main/resources/lib" includes="**/*.jar"/>
</zips>
</archives>
</restrict>
<manifest>
<attribute name="Main-Class" value="com.cibc.ers2.invoker.JobTest"/>
<attribute name="Class-Path" value="./lib/log4j-1.2.16.jar
./lib/org.springframework.context-3.0.3RELEASE.jar
./lib/org.springframework.asm-3.0.3.RELEASE.jar
./lib/junit-4.7.jar
./lib/org.springframework.orm-3.0.3.RELEASE.jar
./lib/org.springframework.transaction-3.0.3.RELEASE.jar
./lib/org.springframework.aspects-3.0.3.RELEASE.jar
./lib/commons-pool-1.5.4.jar
./lib/org.springframework.core-3.0.3.RELEASE.jar
./lib/commons-logging-1.1.1.jar
./lib/HashUtility.jar
./lib/org.springframework.expression-3.0.3.RELEASE.jar
./lib/commons-lang-2.6.jar
./lib/org.springframework.instrument-3.0.3.RELEASE.jar
./lib/mockito-all-1.9.5.jar
./lib/com.springsource.org.aopalliance-1.0.0.jar
./lib/ojdbc14.jar
./lib/commons-io-2.4.jar
./lib/commons-collections-3.1.jar
./lib/org.springframework.jdbc-3.0.3.RELEASE.jar
./lib/spring-batch-infrastructure-2.1.9.RELEASE.jar
./lib/org.springframework.context.support-3.0.3.RELEASE.jar
./lib/commons-dbcp-1.4.jar
./lib/spring-batch-test-2.1.9.RELEASE.jar
./lib/org.springframework.beans-3.0.3.RELEASE.jar
./lib/org.springframework.oxm-3.0.3.RELEASE.jar
./lib/org.springframework.aop-3.0.3.RELEASE.jar
./lib/commons-beanutils.jar
./lib/org.springframework.binding-2.1.1.RELEASE.jar
./lib/spring-batch-core-2.1.9.RELEASE.jar
./lib/org.springframework.test-3.0.3.RELEASE.jar
./launch-context.xml
./log4j.xml"
/>
</manifest>
</jar>
I have also tried zipgroupfileset but that also is giving the same problem.
EDIT
Apologies for not giving enough info about what I am trying to achieve. I have got an application which I am compilint # target/classes. I need to package this application including my class files and dependecies into one jar.
<fileset dir="target/classes">
<exclude name="*.sh"/>
</fileset>
includes all files from target/classes which are not shell scripts.
<restrict>
<name name="**/*.class"/>
<archives>
<zips>
<fileset dir="./src/main/resources/lib" includes="**/*.jar"/>
</zips>
</archives>
</restrict>
It seems like you again include classes and jars here.
If you want only jar change all above to :
<zipfileset dir="./src/main/resources/lib" includes="*.jar"/>
My Question is: How am i able to put files in a subdirectory into my jar via ant? Right now my Code is:
<jar destfile="${dist.dir}\wo42.jar" basedir="bin">
<manifest>
<attribute name="Main-Class" value="org.alternativedev.wo42.App" />
<attribute name="Class-Path" value="lib" />
</manifest>
<zipgroupfileset dir="lib/." excludes="natives/*" />
<fileset dir="data/." includes="." />
It creates a structure like
ROOT-Jar
-org
--bla
-filefromdata1
-filefromdata2
But it should be
ROOT-Jar
-org
--bla
-data
--filefromdata1
--filefromdata2
Do You know what I mean?
Greetings, BigTeddy
Change the last line to
<fileset dir="." includes="data/**" />
No need to copy files around.
An alternative way (which is useful if you want to have the directory in the archive to have a different name) would be
<zipfileset dir="data" includes="." prefix="folder-name-in-jar"/>
First, you create the file structure you need and copy to it all the files required. Then you run jar command on the resulting root directory.
In order to copy files you can use the ANT copy task
For example:
<copy todir="../dest/dir">
<fileset dir="." includes="data/**/*.java">
</fileset>
More on how to pack jar (basics) here
A library that my java application uses needs looks for a file (log4j.xml) in the class path. I use netbeans to manage my project, but I can't find a way to include the lib/ folder.
Netbeans automatically creates a MANIFEST.MF file inside the application jar and also creates a folder called lib/ which includes all dependencies. This manifest specifies a Class-Path attribute that overrides any -cp argument provided on the command line. I can select an arbitrary folder in netbeans' library panel, but it creates a sub folder in the manifest's classpath. I'd like all dependencies and the log4j.xml file inside the lib/ folder.
Hopefully it's possible to do this in the IDE. I include a snippet of the auto-generated build-impl.xml file.
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
Thanks.
Instead of editing the build-impl.xml file you should add this entry to the build.xml file. When you modify anything in your project pertaining to the building of that project, it will generate a new build-impl.xml file.
Here is an example of what I put in my build.xml file:
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete file="${dist.jar}"/>
<delete dir="${dist.dir}/lib"/>
<delete dir="${dist.dir}/resources"/>
</target>
Since I put this in the build.xml file, it will override the "-do-clean" section of the build-impl.xml file which contains:
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
</target>
Furthermore, since it is in the build.xml it won't be modified by Netbeans.
I found a way to acheive this modifying the build-impl.xml.
I changed:
<attribute name="Class-Path" value="${jar.classpath}"/>
to:
<attribute name="Class-Path" value="${jar.classpath} /lib"/>
The problem is that netbeans will overwrite it since this file is automatically generated.
You can simply turn off project option Build/Packaging/Copy Dependent Library and manualy edit manifest.mf in root folder of your project (which is a template for manifest in jar file).
It seems that your problem is the "globmapper" that stores your log4j.xml file in /lib - you'd want it on the "/" or the jar.
I have a standard project layout for a java project:
project /
src /
source_file_1.java
...
source_file_N.java
build /
classes /
source_file_X.class
...
jar /
MyJar.jar
lib /
SomeLibrary.jar
SomeOtherLibrary.jar
As far as I can tell, I am building the project correctly with Ant. I need to set the class-path attribute in the Manifest file so my classes can use the required libraries.
The following relevant information from build.xml
<target name="compile" depends="init">
<javac srcdir="src" destdir="build\classes">
<classpath id="classpath">
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="build\jar\MyJar.jar" basedir="build\classes" >
<manifest>
<attribute name="Built-By" value="${user.name}" />
</manifest>
</jar>
</target>
Any push in the right direction is appreciated. Thanks
Assuming the libraries do not change location from compiling to executing the jar file, you could create a path element to your classpath outside of the compile target like so:
<path id="compile.classpath">
<fileset dir="lib" includes="**/*.jar"/>
</path>
Then you can use the created path inside your javac task in place of your current classpath.
<classpath refid="compile.classpath"/>
You can then use the path to set a manifestclasspath.
<target name="jar" depends="compile">
<manifestclasspath property="jar.classpath" jarfile="build\jar\MyJar.jar">
<classpath refid="compile.classpath"/>
</manifestclasspath>
<jar destfile="build\jar\MyJar.jar" basedir="build\classes" >
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</jar>
</target>
The manifestclasspath generates a properly formatted classpath for use in manifest file which must be wrapped after 72 characters. Long classpaths that contain many jar files or long paths may not work correctly without using the manifestclasspath task.
Looking at my NetBeans-generated build file, I found this snippet in the -do-jar-with-libraries task:
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
So in other words, it looks like you just need to add another attribute to the manifest task that you already have.
See also the Manifest Task documentation.