Jar with dependencies using maven

In the earlier post, though we had dependencies for our jar, we just used them while compiling them. Hence, when we execute our jar, it is required that, they be included in the class-path while executing our jar.

Though, this sounds reasonable enough, there are situations when it becomes tedious to include the dependencies in the class-path every-time you want to run the jar,especially, when there are more than a few dependencies and multiple main-classes. A simpler way is to bundle the other dependent jars in our jar.

Hmmm. This may sound a little off the mark. It is true you cannot bundle the dependent jars in your jar. Albeit, you can include the classes of your dependent jars in your jar. This will solve the problem. Whoa!!! how do i do it?

This can be done pretty easily using Maven in tandem with an assembly.xml. Following are the key points:

a. Use Maven Assembly plugin to assemble the class files in a jar and include their dependencies as well
b. Maven Assembly plugin requires an additional assembly.xml which in turn specifies format e.g. jar and depndency-set
c. Configure the assembly.xml as part of same project and use it from pom.xml using maven assembly plugin
d. Generate one single jar with all dependencies

The sample pom.xml looks like below:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.schoudari.blog</groupId>
  <artifactId>my-blog-reader</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>My Blog Reader</name>
  <properties>
    <log4j.version>1.2.16</log4j.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId><!--1.Use Maven assembly plugin to assemble the jar-->
        <configuration>
          <attach>false</attach>
          <descriptors>
            <descriptor>src/assemble/assembly.xml</descriptor><!--2.Assembly configuration-->
          </descriptors>
          <archive>
            <manifest>
              <mainClass>com.schoudar.blog.MyBlogReader</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
    </dependency>    
  </dependencies>

</project>

The sample assembly.xml is specified below:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
  <id>jar-with-dependencies</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <unpack>true</unpack>
      <scope>runtime</scope>
    </dependencySet>
  </dependencySets>
</assembly>

Useful Links:
http://www.ibm.com/developerworks/java/library/j-5things13/index.html

Creating a Jar using Maven

In the earlier post, we had seen how to create a jar, in this post we will see how to create a jar using maven. Following are key points in creating the jar using maven.

1. Specify the packaging type e.g. jar.

2. Compile the source code. Use  maven-compiler-plugin here.

3. Generate eclipse related files like .classpath, etc. Use maven-eclipse-plugin. [optional]

4. Bundle the java class files in a jar. Use maven-jar-plugin.

5. Provide the main-class[entry point] for your jar in the mainfest.

6. Execute the unit-tests of your jar before creating the jar. [optional]

Refer to the sample pom.xml below:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.schoudari.blog</groupId>
  <artifactId>my-blog-reader</artifactId>
  <packaging>jar</packaging> <!--1.Packaging Type -->
  <version>1.0.0-SNAPSHOT</version>
  <name>Blog Reader</name>

  <properties>   
    <log4j.version>1.2.16</log4j.version>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId> <!--2.Compiles the source-code -->
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId> <!--3.Generates the eclipse-related files -->
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId><!--4.Creates a jar -->
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>com.schoudari.blog.BlogReader</mainClass><!--5.Add main class -->
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId><!--6.Executes the unit-test cases -->
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
    </dependency>       
  </dependencies>  
</project>

Basics of Jar

A few years back, i was asked why a class in jar was not running as expected from command prompt. The answer was quite simple, the dependencies of the class are not available.

There is a common misconception that you create a jar and everything runs out of the box for you when you run the main class. Now what is the main class in the jar. Let me give you some introduction to jars:

a. Jar – Java archive. As the name says, it archives a set of java files.

b. Common Jar Operations

Operation Command
To create a JAR file jar cf jar-file input-file(s)
To view the contents of a JAR file jar tf jar-file
To extract the contents of a JAR file jar xf jar-file
To extract specific files from a JAR file jar xf jar-file archived-file(s)
To run an application packaged as a JAR file (requires the Main-class manifest header) java -jar app.jar

c. In general, a java file uses some or the other open source libraries e.g. log4j.jar, etc. Hence, when we create a jar, it is required that it is available in the class-path when we are creating the jar, so the class files can be created and then, they can be bundled. The same principles applies when you execute the jar file as well.

d. Every jar should have at-least one Main-class. Main-class is a class, which is a public class, with the public static void main(String[] args) method. This is the entry-point for all the classes in your jar. P.S. There can be more than one main class as well. In such a case, it is preferable not to have a main-class specified in the manifest.

e. A jar generally comes with a MAINFEST file. This is like meta-information about a jar. e.g.

Manifest-Version: 1.0
Main-Class: MyClass
Class-Path: MyUtils.jar
Created-By: 1.6.0 (Sun Microsystems Inc.)

Useful links:
http://docs.oracle.com/javase/tutorial/deployment/jar/index.html

Difficult Java interview questions – Serialization

This article is a follow-up to my article here

a. Are static variables serializable?

Ans: Static and transient variables of a class are not serializable. 

b. Can a class implement both Serializable and Externalizable?

Ans: Yes, the class can implement both Serializable and Externalizable.

c. What happens to the non-serializable objects in a class while serializing which implements Serializable?

Ans: The class fails to serialize with exception  java.io.NotSerializableException.

d. What happens to the non-serializable objects in a class while serializing which implements Serializable, Externalizable?

Ans: The class can be serialized and de-serialized successfully.

e. How do we deal with serialVersionUID when a class implements Serializable?

Ans:  If we don’t provide a serialVersionUID,  java compiler generates a serialVersionUID based on the properties defined in the class. Hence, if we have modified the class with a new property after a class has been serialized, then it will fail while de-serializing as a new serialVersionUID is generated by java compiler again. So, to get around this issue, we can fix the serialVersionUID of a class to be 1L. 

f. If we have a Serializable class “MyClass” which extends “MySuperClass”. What happens to the properties of “MySuperClass”, when we serialize/de-serialize “MyClass”?

Ans: If the properties inside the “MySuperClass” are serializable like primitives,serializable classes then all these will be available in the sub-class during/after serialization. However, if there are non-serializable properties, then there should be a default constructor in “MySuperClass” provided.

g. How do we serialize the non-serializable properties of a super-class[non-serializable] in a serializable sub-class?

Ans: We will have to over-ride the default private writeObject() and readObject() methods of sub-class and provide values for the non-serializable properties. Otherwise, ensure that the non-serializable properties are set with some default/specific values while creating the sub-class it-self. Refer below for sample code:

import java.io.*;

public class TestSerialization {
    public static void main(String args[]) {
        // Object serialization
        try {
            MyClass object1 = new MyClass("Hello");
            System.out.println("object1: " + object1);
            FileOutputStream fos = new FileOutputStream("serial");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(object1);
            oos.flush();
            oos.close();
        } catch (Exception e) {
            System.out.println("Exception during serialization: " + e);
            System.exit(0);
        }
        // Object deserialization
        try {
            MyClass object2;
            FileInputStream fis = new FileInputStream("serial");
            ObjectInputStream ois = new ObjectInputStream(fis);
            object2 = (MyClass) ois.readObject();
            ois.close();
            System.out.println("object2: " + object2);
        } catch (Exception e) {
            System.out.println("Exception during deserialization: " + e);
            System.exit(0);
        }
    }
}

class FailSerilization{
    String y="fail serilization";
}

class MySuperClass{
    String x="not super";
    FailSerilization fs;

//    MySuperClass(FailSerilization fs){
//        this.fs=fs;
//    }
    MySuperClass(){
        fs=new FailSerilization();
    }

}

class MyClass extends MySuperClass implements Serializable {
    String s;

    public MyClass(String s) {
        //super(new FailSerilization());
        this.s = s;

    }

    public String toString() {
        return "s=" + s + ";x= "+x+"; fs= "+fs.y;
    }
}

More here:

class MyClass extends MyClass2 implements Serializable{

  public MyClass(int quantity) {
    setNonSerializableProperty(new NonSerializableClass(quantity));
  }

  private void writeObject(java.io.ObjectOutputStream out)
  throws IOException{
    // note, here we don't need out.defaultWriteObject(); because
    // MyClass has no other state to serialize
    out.writeInt(super.getNonSerializableProperty().getQuantity());
  }

  private void readObject(java.io.ObjectInputStream in)
  throws IOException {
    // note, here we don't need in.defaultReadObject();
    // because MyClass has no other state to deserialize
    super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
  }
}

/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {

  /* this property must be gettable/settable by MyClass.  It cannot be final, therefore. */
  private NonSerializableClass nonSerializableProperty;

  public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
    this.nonSerializableProperty = nonSerializableProperty;
  }

  public NonSerializableClass getNonSerializableProperty() {
    return nonSerializableProperty;
  }
}

class NonSerializableClass{

  private final int quantity;

  public NonSerializableClass(int quantity){
    this.quantity = quantity;
  }

  public int getQuantity() {
    return quantity;
  }
}

Effective Logging in Java/JEE

It all started when i was sitting with a colleague to resolve some application issue, when i noticed something interesting. He was merging the code and my eyes caught the attention of this class “org.apache.log4j.MDC”. This led to few discoveries on the way which  follow here:

What is MDC?

MDC stands for Mapped Diagnostic Context. It helps you to distinguish inter-leaving logs from multiple sources. Let me explain in detail. When we have multiple user-requests coming in for a given servlet, each request of an user is serviced using a thread. This leaves multiple users logging to the same log file and the log statements get inter-mixed. Now, to filter out logs of a particular user, we need to append the user-id to the log statements so that we can grep(search) them in the log file, to make some sense of it.

An obvious way of logging, is to append the user-id in the log statements i.e. log.info(userId+” logged something “);

A non-invasive way of logging is to use MDC. With MDC, you put the user-id in a context-map which is attached to the thread (of each user request) by the logger.

MDC is thread-safe and uses a Map internally to store the context information.[Courtesy : Kalyan Dabburi]

How to use MDC?

a. Configure the information, which needs to be logged (user-id in this case) in the log4j.xml as part of ConversionPattern.

log4j.appender.consoleAppender.layout.ConversionPattern 
= %d %i - %m - %X{user-id}%n

b. In your respective class, before you start processing the user request, place the actual user-id in the context(MDC).

MDC.put("user-id","SKRS786");

c. Remove the context information from MDC at the end of the processing.

MDC.remove("user-id");

References :

Logback implementation

Log4J implementation

 

What is NDC ? Which one to use MDC or NDC?

NDC stands for Nested Diagnostic Context. It is a stack-based implementation of attaching context information. For all purposes, use MDC over NDC, as MDC is memory efficient. For a detailed comparison, click here.

Which logging framework to use? Log4J or SLF4J or logback?

For all new application development, use logback. logback is a run-time implementation of SLF4J. If you have an existing application with Log4J, it is still worth-while to switch to logback. For a detailed explanation, click here.

To understand the evolution of logging in Java and JEE world, refer to this article by Micheal Andrews.

 

Purpose of ContextLoaderListener – Spring MVC

When we are working with Spring MVC and are also using Spring in the services layer, we provide two application-contexts. The first one is configured using ContextLoaderListener and the other with DispatcherServlet. A sample configuration in web.xml is mentioned below:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>    
        /WEB-INF/config/applicationContext-service.xml
        /WEB-INF/config/applicationContext-dao.xml
    </param-value>
</context-param>
<servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/config/servlet-context.xml
           ***/WEB-INF/config/applicationContext.xml***
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

After reading the Spring documentation, following is the understanding:

a) Application-Contexts are hierarchial and so are WebApplicationContexts. Refer documentation here.

b) ContextLoaderListener creates a root web-application-context for the web-application and puts it in the ServletContext. This context can be used to load and unload the spring-managed beans ir-respective of what technology is being used in the controller layer(Struts or Spring MVC).

c) DispatcherServlet creates its own WebApplicationContext and the handlers/controllers/view-resolvers are managed by this context.

d) When ContextLoaderListener is used in tandem with DispatcherServlet, a root web-application-context is created first as said earlier and a child-context is also created by DispatcherSerlvet and is attached to the root application-context. Refer documentation here.

Refer to the diagram below from the Spring documentation.

Reverse the order of a Sentence in Java

Recently, in an interview, i was asked to reverse a sentence, i.e. given a String “THIS IS AN INTERVIEW” , reverse it to “INTERVIEW AN IS THIS” without using any advanced APIs of Java.

I had tried to solve the problem with the java.util.regex.Pattern class after realizing that usage of StringTokenizer is discouraged in the Java Docs. However,the solution was not accepted as it used Pattern class. So, i was determined to solve the problem myself and have come up with the below solution. Please provide your valuable feedback. The soultion here uses basic classes like String, StringBuilder and char. The solution here can be enhanced for a character-sequence. Currently, it works only for a single character.

import java.util.regex.Pattern;

public class TestStringSplitAndReversal {

    public static void main(String args[]) {
        String testString = "THIS IS A TEST";
        char regex = ' ';
        String[] reversedString = TestStringSplitAndReversal.split(regex, testString);
        int size = reversedString.length;
        //For String reversal
        for (int i = size - 1; i >= 0; i--) {
            if (reversedString[i] != null)
                System.out.println("Element:::" + reversedString[i]);
        }
    }

    // Regular Splitting using Java's API
    public static String[] split(String regex, String str) {
        return Pattern.compile(regex).split(str);
    }

    // Splitting without using any advanced APIs of Java
    public static String[] split(char regex, String str) {
        char[] actual = str.toCharArray();
        // char[] temp=new char[str.length()];
        StringBuilder tempStr = new StringBuilder();
        int j = 0, k = 0;
        String[] result = new String[str.length()];
        int resultSize = 1;
        for (int i = 0; i < actual.length; i++) {
            // temp[j++]=actual[i];
            tempStr = tempStr.append(actual[i]);
            if (regex == actual[i]) {
                result[k++] = new String(tempStr);
                // j=0;
                resultSize++;
                // temp=new char[str.length()];
                tempStr = new StringBuilder();
            }
        }
        // result[k++]=new String(temp);
        result[k++] = new String(tempStr);
        return resizeArray(result, resultSize);
    }

    //This resizing is required as once an Array is initialized to a size, 
    //it cannot be shrinked.Hence, we need to create a new Array.
    public static String[] resizeArray(String[] original, int resultCount) {
        String[] result = new String[resultCount];
        for (int i = 0; i < original.length; i++) {
            if (original[i] != null) {
                result[i] = original[i];
            }
        }
        return result;
    }

}