Java: How to compile a runnable jar from packages? - java

My Java application has got a package structure similar to this:
src/com/name/app
src/com/name/app/do
src/com/name/utils/db
How would I go about compiling Java files in these directories in to a runnable jar? I need to package required libraries into the generated JAR (jdbc).
I've always done these things in Eclipse but now I need to supply a couple of people with a way to compile the repository without the use of eclipse and I was thinking of making a makefile or a script that invokes the necessary javac pattern.

Take a look at Ant. It's a relatively simple build tool to understand, and provides everything that meets your requirements. Here's a quick skeleton build.xml to get you started:
<project name="my_app_name" default="jar">
<target name="compile">
<javac srcdir="src" destdir="bin">
<classpath>
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
<target name="jar">
<jar manifest="manifest_file" destfile="dist/my_app_name.jar">
<fileset dir="bin" />
<fileset dir="lib" />
</jar>
</target>
You need to create a manifest file that will tell the java process which class holds the "main" method. Here is a good place to start learning about manifests.
As an alternate that produces really cluttered Ant build files, you can right click on your Eclipse project and choose "Export...", then choose "General > Ant Buildfiles".
Anyway, that should get you started. You can ask more specific questions as you run into them.

First of all, consider using Ant for such a task.
But since you asked for a manual process, you need to first create a manifest file, like so:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Class-Path: lib/jdbc.jar lib/otherlib.jar
Main-Class: com.name.app.MainClass
Replace the contents of Class-Path with your libs, and Main-Class with the fully qualified name of your main class.
Then, you need to generate the actual .jar, using the following command:
jar cfm app.jar MANIFEST.MF src/com/name/app/*.class src/com/name/app/do/*.class
Where MANIFEST.MF is the previously mentioned manifest file, and the rest is the folders where your .java classes lie in.
Finally, to run your app, you simply execute: java -jar app.jar.

Consider using Ant to do this. http://ant.apache.org/

I recommend that you use Apache Ant to implement your build scripts.
If implemented correctly, Ant is easy to use and the build scripts can be run on any platform that you can install a JDK on. Indeed, with a little bit of work, you can even set up your project so that users don't even need to download / install Ant. (Hint: add the Ant JAR files and a wrapper script to your project distro)

Related

.POST_MODULE: Failed to process phase POST_MODULE of deployment

I'm trying to generate a war using an Ant script, but it seems that it won't run on jboss. Anyone knows the diference between this and create a war using Eclipse(File ->Export -> War)?
<war warfile="${docflow4-web-home}/deploy/${nome}.war" webxml="web/WEB-INF/web.xml">
<fileset dir="${docflow4-web-home}/web">
</fileset>
</war>
In Eclipse, optionally, there is a supply WAR export Options, such as whether or not to include Java™ source files in the WAR, and whether to overwrite any existing resources during the export process. Source files are not usually included in a WAR file, because they are not necessary for the server to run the web application. Otherwise, everything is similar to ant script.
In Ant script, your script seems alright, but it is aways nice using the tag , for example: <classes dir="${classes.dir}" /> because it defines a grouping to specify what goes into the WEB-INF\classes folder.
If you are using some third part jar, use the tag lib too, example:
<lib dir="thirdpartyjars">
<exclude name="portlet.jar"/>
</lib>

Using Ant to build multiple jars

I have multiple Java eclipse projects. Each of them has "jardesc" file for building jar. It's nice - double click -> finish and jar file is made. But when i have to export several jars it's a pain - i have to repeat procedure several times.
Please tell me, can i use Ant script to run several "jardesc" files at once (and get several jars according to each jardesc file)? How to do it?
You could use the jar target to make the jars for you:
<jar destfile='destination.jar' basedir='source\dir\' />
so your build.xml would look a little like this:
<project default="makejars">
<target name="makejars">
<jar destfile="app1.jar" basedir="app1\src\" />
<jar destfile="app2.jar" basedir="app2\src\" />
<jar destfile="app3.jar" basedir="app3\src\" />
</target>
</project>
then just run ant in the same directory as build.xml, and the jars should be made.
Take a look at subant task in ant. You can create ant-file which would call other files to.
<subant target="create_jar1">
<fileset dir="." includes="jar2.xml"/>
</subant>
<subant target="create_jar2">
<fileset dir="." includes="jar1.xml"/>
</subant>
You can use some loops to create ant parameters however there is no way to loop to create multiple jars (even with ant-commons extension), a copy & paste is the only viable solution unless you want to write an ant plugin (which doesn't really take that much 2 hours reading docs + write simple plugin)

Ant build using two projects

I have two separate projects inside of eclipse: "project" and "pinclude"
Project includes pinclude, so without somehow include the java files for that project inside of my build.xml, javac will always return errors.
How do I got about including .class files inside of ant/javac? I've tried searching for a solution, but so far I've only came up with ways of adding jar files. Would creating a jar of all the "pinclude" .class files fix my problem?.
Thank you for your help.
NOTE:
I'm sorry for the poor naming convention; These are just projects I made to figure out this problem out.
Also, please ignore srcdir and destdit, they are not important.
Build.xml
<project name="project" basedir="." default="dist" >
<target name="dist" >
<javac destdir="bin"
srcdir="${basedir}\myfileslocation\" >
</javac>
</target>
How do I got about including .class files inside of ant/javac? I've
tried searching for a solution, but so far I've only came up with ways
of adding jar files. Would creating a jar of all the "pinclude" .class
files fix my problem?.
Yes. It helps to separate functionality into smaller modules. If you export one project (pinclude in this case) into a jar and import(via classpath) in another , that is the most correct step.
I'm not 100% sure what you need. Are you saying that you have class files from pininclude, and you need to include them in your <javac> compile task? It would be something like this:
<javac destdir="bin"
srcdir="${basedir}/myfileslocation">
<classpath>
<pathelement path="${path.to.pininclude.javac.files}"/>
</classpath>
</javac>

Setting Class-Path in Ant build script

I'm trying to build my console application and I'm using Ant to build it. I can run my application in Eclipse, but when I try to run it from jar that I get - the ClassNotFoundException: is thrown. is in one of jars, that I use for my application. Here is a part of build.xml where I create manifest:
<manifest>
<attribute name="Main-Class" value="com.package.Reporter" />
<attribute name="Class-Path" value="lib/commons-httpclient-3.1.jar
lib/commons-logging-api.jar
...lot of jars...
lib/stax-api-1.0.1.jar" />
</manifest>
The required class is in commons-httpclient-3.1.jar
And here is how I set up classpath for compiling, that is fine:
<path id="libs.dir">
<fileset dir="lib" includes="**/*.jar"/>
</path>
UPD: Should I put jars with libs to my jar? Now I'm putting them to "lib" directory of my jar. So myjar.jar contains package with my classes, META-INF directory and lib directory.
Max, you can't insert jar libs into jar, assuming normal usage. Either you don't have to specify them manually at runtime as Romski suggested. When invoking java -jar myjar.jar it should locate all your jars provided that they are located in the lib directory. lib directory must be in the same directory that jar resides in. Doesn't matter if you call java executable directly or through ant java task.
Note that the current directory doesn't matter only the relation between the jar and the lib.
Now being overly explicit. Perform sanity test as follows: create a new tmp directory and copy files to it:
tmp/myjar.jar
tmp/lib/commons-httpclient-3.1.jar
Run java -jar tmp/myjar.jar
Edit: now I see I just wrote the same what is in Oracle jar tutorial. But I also made tests myself with a relative directory. I also see dozens of stackoverflow questions searching for jar in jar so please first search SO, then ask.
try to change the path like this.
<path id="libs.dir">
<fileset dir="./lib" includes="**/*.jar"/>
</path>
You need the manifestclasspath task.
Example:
Ant - how to get all files' name in a specific folder

Nested jar files

a question on building executable jar files. Suppose we have a jar file a.jar that contains UI.class. I have used a metafile in archiving a.jar that says
Main-Class: UI
Class-Path: . b.jar c.jar
Now, if I want to ship this executable a.jar to somebody, I have to ship 3 files - a.jar, b.jar and c.jar. The user has to put all 3 in the same folder, and then double clicking on a.jar would work. It would be simpler if I could ship a single file (a.jar), and the JVM could figure out to extract b.jar and c.jar from in there to use the classes. These 2 are external libraries and I dont want to expand them and re-jar the class files in a.jar.
Can this be done? If so, what is the jar command and what should go in the metafile? Currently the command is
jar cmf metafile a.jar UI.class
Thank you.
Have you looked at this tool OneJar? Also this is a good article to read on OneJar.
If you decide to not use an external tool then your alternative is to put the library/helper jars in the classpath in the manifest, and then copy the jars themselves in a directory path relative to your main jar.
EDIT: OP asked for an example MANIFEST.MF. I coped this from the example One-Jar example jar file.
Manifest-Version: 1.0
Main-Class: com.simontuffs.onejar.Boot
One-Jar-Expand: expand,doc
There is OneJar as people have mentioned but also (especially if you are using eclipse) you can consider fatjar.
ALternatively, you can also achieve this by using an ANT Task here's an example:
<target name="dist" depends="compile,static" description="Compiles and builds jar files">
<mkdir dir="${dist}"/>
<jar destfile="${dist}/MYAPP.jar">
<zipfileset src="${dist}/MY_OTHER_APP.jar"/>
<zipfileset src="${lib}/commons-io-1.4/commons-io-1.4.jar"/>
<zipfileset src="${lib}/commons-math-2.1/commons-math-2.1.jar"/>
<fileset dir="${res}" includes="*"/>
<manifest>
<attribute name="Main-Class" value=<where your main class is>/>
</manifest>
</jar>
</target>
OneJar is good for just bundling a few things together, but it's generally quite slow and inflexible. This isn't a dig at OneJar, it's great for what it does but unless I wanted a quick and easy distributable for a tiny program I wouldn't use it.
I did use it for a while but then switched to izpack. It provides an installer as a single jar which I've found to generally work very well, and supports things such as windows specific shortcuts as well. It's also really easy to integrate it with ant.
Another way can be use one of several available tools to create a setup deliverable and your setup pack will unpack your application when installed.
Maven users can also use the assembly plugin for this:
http://maven.apache.org/plugins/maven-assembly-plugin/usage.html

Categories