Wednesday 13 February 2013

Compile and Run Multiple Java Classes From Command Prompt.

It sounds silly to write a post for java file compilation and execution. But I took one hour to find the problem.

If you have multiple java files and all of them are in different packages. Then how can you compile them and run main class among them. Let me take an example
Consider two classes in a package com.test.
com.test.MainClass
com.test.UtilityClass


Compilation: If you go inside and compile using javac mainclass, you will be thrown an error
MainClass : Cannot find location

Similarly if you have class files in a package and if you try to execute,using java mainclass command, then system will throw following error.

Exception in thread "main" java.lang.NoClassDefFoundError: <ClassName> (wrong nam
e: com/test/<ClassName>)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

Problem here is we go inside the folder com/test and try to compile or run files. But
Never go inside packaged folder(com or test) and try to run the files. 
Come out of the package folder and run the commands. 
Compilation: 
javac ./com/test/MainClass.java
javac ./com/test/Utilities.java

Execution:
java com.test.MainClass.java
 

Friday 8 February 2013

Ant For Beginners


  • Download Apache Ant Binary Distributions from here
  • Set path to %ANT_HOME%/bin (Type ant -version to test whether path is set or not).
  • Now we need a build.xml to create folder hierarchy.
  • Here is a basic build.xml which will create src, resources, build folders. These are not standard folders. One can create their own folders and define the folder hierarchy by modifying build.xml. In the following build.xml, I have created src folder to put source code(Some times properties files also), resources folder to keep all the resources(images, data files etc) and build folder to keep class files and JAR file.
  • Just copy following code in a file and save it as build.xml. Go to the path and type
      ant run
  • If you have a source code already then copy your source code in src folder, resources in resources folder and re- run ant.


<?xml version="1.0" encoding="UTF-8"?>
<project name="InfraTransform" default="build-jar" basedir=".">
    <property name="src.dir" value="src" />
    <property name="build.dir" value="build" />
    <property name="resources.dir" value="resources" />
    <property name="classes.dir" value="${build.dir}/classes" />
    <property name="jar.dir" value="${build.dir}/jar" />
    <property name="lib.dir" value="lib" />
    <property name="main-class" value="com.test.MainClass" />

    <path id="classpath">
        <fileset dir="${lib.dir}" includes="*.jar" />
    </path>

    <pathconvert property="manifest.classpath" pathsep=" ">
        <path refid="classpath" />
        <mapper>
            <chainedmapper>
                <flattenmapper />
                <globmapper from="*.jar" to="${lib.dir}/*.jar" />
            </chainedmapper>
        </mapper>
    </pathconvert>

    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <target name="compile" depends="clean">
        <mkdir dir="${classes.dir}" />
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" />
    </target>

    <target name="build-jar" depends="compile">
        <mkdir dir="${jar.dir}" />
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <fileset dir="${resources.dir}" includes="**/*.*" />
            <fileset dir="${src.dir}" excludes="**/*.java" />
            <manifest>
                <attribute name="Built-By" value="${user.name}" />
                <attribute name="Main-Class" value="${main-class}" />
                <attribute name="Class-Path" value="${manifest.classpath}" />
            </manifest>
        </jar>
    </target>

    <target name="run">
        <java fork="true" classname="${main-class}">
            <classpath>
                <path refid="classpath" />
                <path location="${jar.dir}/${ant.project.name}.jar" />
            </classpath>
        </java>
    </target>


</project>

Let's try to understand the build.xml a bit.
  • In general build.xml starts with project tag, and property tags are used to define some constants, so that we can refer those names in the rest of the code.( In our example, we used properties to define folder paths).
  • If you have more properties, then keep all the properties in a file and name the files as build.properties. Refer this file as property in build.xml.
          <property file="build.properties"/>
  • Let's see a sample build.properties
         src.dir = src
         build.dir = build
        resources.dir = resources
        classes.dir = ${build.dir}/classes
        jar.dir = ${build.dir}/jar
       lib.jar = lib
       main-class = com.test.MainClass


  • target in build.xml is like function in traditional programming. Write your logic(Creating directories/files, deleting them, running instructions etc) in a block and name that block as target name = "somename". You can call function from command prompt.
      ant <targetname>
  • depends name it self tells us that before this function runs, there is a dependent function which needs to be run.
I think, this is enough to start ant, if you understand a bit, then go through official material and other sources.

Further Reading:
Tutorial: Hello World with Apache Ant
Apache Ant - Tutorial

Saturday 2 February 2013

Ant Script: How To Pack Multiple Jars In A Single Script

As we know that, pack200 is the best compression tool to compress java classes(In my experience, it compresses one third to one ninth of its original size). Sometimes we need to pack a bundle of jar files(Especially library files), but it is hard to use command line syntax to bundle them all in a single shot. But ant will help us to automate this, even if you don't know ant , don't worry. Just follow these steps.

Steps to pack multiple jars
  • Download ant from here
  • Set %ANT_HOME% as path variable and add ant/bin to path.
  • Create a file and name it build.xml. (If you don't know any thing about build.xml, just copy following code and save it as build.xml).
<project>
<property name="dir.jar" value="
Source_Folder"/>
<apply executable="pack200" parallel="false" dest="
Destination_Folder">
        <arg value="--modification-time=latest"/>
        <arg value="--deflate-hint=true"/>
        <arg value="--segment-limit=-1"/>
        <targetfile/>
        <srcfile/>
        <fileset dir="${dir.jar}/" includes="**/*.jar" />
    <mapper type="glob" from="*" to="*.pack.gz" />
 </apply>
</project>


In the preceding code snippet, Source_Folder and Destination_Folder are user defined folders. Make sure that your jar files are in source_folder and these two folders should be in the same folder as build.xml .
  • Final step is, type ant. 
Done... Your packed jars with extenstion pack.gz will be created in Destination_Folder.