Saturday, March 8, 2014

Java Serialization

Serialization is the process of converting the current state of an object into a byte stream. Deserialization is the process of converting the serialized form of an object back into a copy of the object.  A Java object is Serializable if a class implements java.io.Serializable interface. java.io.Serializable is a marker interface which tells that object is Serializable.

A quick example. In this example Employee class implements the marker interface Serializable and can be serialized. 
package com.sourcetricks.java;

import java.io.Serializable;

public class Employee implements Serializable {

 private static final long serialVersionUID = 2L;
 private int id;
 private String name;
 private int deptId;
 Employee() {   
 }
 Employee(int id, String name, int deptId) {
  this.id = id;
  this.name = name;
  this.deptId = deptId;
 }
 public int getId() {
  return id;
 }
 public String getName() {
  return name;
 }
 public int getDeptId() {
  return deptId;
 }
 public void setId(int id) {
  this.id = id;
 }
 public void setName(String name) {
  this.name = name;
 }
 public void setDeptId(int deptId) {
  this.deptId = deptId;
 }
 public void print() {
  System.out.println(id);
  System.out.println(name);
  System.out.println(deptId);
 }
}

In the test program we create an instance of Employee and using writeObject on ObjectOutputStream we persist the serialized object to the file system. During deserialization we do the reverse using readObject on ObjectInputStream to create a copy of the object back.
package com.sourcetricks.java;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class JavaSerializationTest {
 
 public static void main (String[] args) {
  
  Employee e = new Employee(100, "John", 14);
  e.print();
  
  // Serialize and save the object to file
  FileOutputStream fout = null;
  ObjectOutputStream out = null;
  try {
   fout = new FileOutputStream("data.out");
   out = new ObjectOutputStream(fout);
   out.writeObject(e);
   out.close();
   fout.close();
  } catch (IOException e1 ) {
   e1.printStackTrace();
  }
  
  // Read object from file
  FileInputStream fin = null;
  ObjectInputStream in = null;
  try {
   fin = new FileInputStream("data.out");
   in = new ObjectInputStream(fin);
   Employee e1 = (Employee) in.readObject();
   e1.print();
   in.close();
   fin.close();
  } catch (IOException e1 ) {
   e1.printStackTrace();
  } catch (ClassNotFoundException e2) {
   e2.printStackTrace();
  }
 }
}
Output:
100
John
14
100
John
14

Sgnificance of serialVersionUID

serialVersionUID is important for classes to be serialized. It allows to specify a version to the object. Lets say object version is 1 when the object was written to the file system. At a later point of time there is a type change in the object and the version is upgraded to 2. If we try to deserialize the original object written to file system then it results in an InvalidClassException. 

java.io.InvalidClassException: com.sourcetricks.java.Employee; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

Significance of transient

Sometimes it is necessary that one of the class members should not be included as part of the serialization process. Either it has sensitive information or which is not relevant once the object is de-serialized. (e.g. current time). In such scenarios associating transient keyword prevents the class member from being included as part of writeObject.

Saturday, February 22, 2014

FreeMarker Introduction

FreeMarker Introduction

FreeMarker is a template engine that helps to generate text based on templates. Examples, generation of dynamic web pages, source code generators etc. Freemarker helps to separate the application logic and page design. FreeMarker is a Java library and is free to use with the BSD license terms.

FreeMarker supports a powerful template language which helps to bind a data-model and template together to produce the output.

Data Model 

All the data that the template can use/ refer is packed into a data-model. From the perspective of the template the data-model is a tree structure holding data. The data model tree can contain scalars that store a single value, containers that store other variables or sequences that store other variables in an ordered sequence.

Template

Templates use FTL tags (Freemarker Template Language) tags that provide instructions to FreeMarker. All the Freemarker tags start with #. 

FreeMarker Download

To use the examples below download Freemarker from http://freemarker.org/ and include the freemarker.jar in the application CLASSPATH. There are no other dependencies.

Freemarker Example

This example is an introduction to get quickly started with FreeMarker and understand the basic usage principles. Let's say we are interested in reporting a list of books (preferably in database) as a HTML table.

Data Model Example

First step is to create the data model. For simplicity we have ignored reading the actual data from database but instead fill our data model with some static data. Here we create a data model with a list of books and a scalar variable with report generated date interpreted as string.

// Create a data-model      
Map<String, Object> root = new HashMap<String, Object>();
List<Object> bookList = new LinkedList<Object>();
bookList.add(new Book("Gambardella, Matthew", "XML Developer's Guide"));
bookList.add(new Book("Ralls, Kim", "Midnight Rain"));
bookList.add(new Book("Corets, Eva", "Maeve Ascendant"));
root.put("bookList", bookList);

Date now = new Date();
root.put("ReportDate", now.toString());

For reference here is the Book class we use.

package com.sourcetricks.freemarker;

public class Book {

    private String author;
    private String title;
 
    public Book(String author, String title) {
       this.author = author;
       this.title = title;
    }
 
    public String getAuthor() {
       return author;
    }
 
    public String getTitle() {
      return title;
    }
}

Template Example

In this template we use FTL tags to bind data in our model to the HTML page. We use <#if> to check if books are present and <#list> to parse the book list. 

<!DOCTYPE html>
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <#if bookList??>
     <p>No of books = ${bookList?size}</p>
     <table border="1">
       <tr>
         <th>Author</th>
         <th>Title</th>
       </tr>
       <#list bookList as book>
       <tr>
         <td>${book.author}</td>
         <td>${book.title}</td>
       </tr>
       </#list>
      </table>
   <#else>
       No books found
   </#if>
   <p>Reported at: ${ReportDate}</p>
</body>
</html>  

Main Program

Here is our main program which binds the data model and the template together and produces the required HTML page output.

package com.sourcetricks.freemarker;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.Version;

public class FreemarkerTest {

  public static void main (String[] args) {
  
    // Create and adjust the configuration. Needed once for the application.
    Configuration cfg = new Configuration();

    try {
      cfg.setDirectoryForTemplateLoading(new File("resources"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    
    cfg.setObjectWrapper(new DefaultObjectWrapper());
    cfg.setDefaultEncoding("UTF-8");
    cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
    cfg.setIncompatibleImprovements(new Version(2, 3, 20));
    
    // Create a data-model      
    Map<String, Object> root = new HashMap<String, Object>();
    List<Object> bookList = new LinkedList<Object>();
    bookList.add(new Book("Gambardella, Matthew", "XML Developer's Guide"));
    bookList.add(new Book("Ralls, Kim", "Midnight Rain"));
    bookList.add(new Book("Corets, Eva", "Maeve Ascendant"));
    root.put("bookList", bookList);
    
    Date now = new Date();
    root.put("ReportDate", now.toString());
        
    try {
      // Get the template from the configured directory
      Template temp = cfg.getTemplate("test.ftl");
   
      // Process the template to merge data model 
      Writer out = new FileWriter("output.html");
      temp.process(root, out);
    } catch (IOException e) {
      e.printStackTrace();
    } catch (TemplateException e) {
      e.printStackTrace();
    }        
  }
}

Output



Sunday, February 9, 2014

Log4j properties configuration examples

Refer to this article Using Log4j for debugging in Java for a quick introduction on Log4j. Log4j is a simple, reliable, fast and extensible open source logging and tracing API. Logging is an important part of any software development lifecycle and is the only way to debug in certain production systems where it is not feasible to use debuggers. Here we provide most commonly used properties configuration examples.

Log to console only

# Set root logger
log4j.rootLogger=DEBUG, console

# Add log messages to console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n

Log to file only

# Root logger option
log4j.rootLogger=DEBUG, file

# File appender
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n
log4j.appender.file.File=myoutput.log
log4j.appender.file.MaxFileSize=100KB

Log to both console and file

# Root logger option
log4j.rootLogger=DEBUG, file, console

# Direct log messages to stdout
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n

# File appender
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n
log4j.appender.file.file=myoutput.log
log4j.appender.file.MaxFileSize=100KB

Log to both console and file and with different log levels

# Root logger option
log4j.rootLogger=TRACE, file, console

# Direct log messages to stdout
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n
log4j.appender.console.Threshold=TRACE

# File appender
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n
log4j.appender.file.file=myoutput.log
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.Threshold=DEBUG

Log to console and customize level based on package

# Set root logger
log4j.rootLogger=TRACE, console

# Add log messages to console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n
log4j.logger.com.sourcetricks=DEBUG

Using Log4j for debugging in Java

Log4j is a simple, reliable, fast and extensible open source logging and tracing API. Logging is an important part of any software development lifecycle and is the only way to debug in certain production systems where it is not feasible to use debuggers.

To use these examples download Log4j from https://logging.apache.org/log4j/1.2/.

Let us quickly start with something minimal and the then try to understand Log4j terminology and APIs.

Using Log4J BasicConfigurator to log debug messages to the console

In this example we create a static logger instance and initialize using a basic configurator which logs all debug messages to the console.

package com.sourcetricks.log4j;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class Log4jTest {
  // Initialize logger for instance Log4jTest
  static Logger log  = Logger.getLogger(Log4jTest.class);
    
  public static void main (String[] args) {
    // Basic configurator to log debug messages to the console
    BasicConfigurator.configure();         
          
    // Add some log messages
    log.debug("This is a debug message");
    log.trace("This is a trace message");         
  }
}

Output
0 [main] DEBUG com.sourcetricks.log4j.Log4jTest  - This is a debug message

Using Log4J BasicConfigurator to log all messages to the console

In this example we set the log level to log all messages to the console. Only difference from the previous example is that we have set the log level to log all messages to the console. Please note that in the output we get both the log messages unlike the previous example.

package com.sourcetricks.log4j;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class Log4jTest {
  // Initialize logger for instance Log4jTest
  static Logger log  = Logger.getLogger(Log4jTest.class);
    
  public static void main (String[] args) {
    // Set the level to log all messages
    log.setLevel(Level.ALL);

    // Basic configurator to log all messages to the console
    BasicConfigurator.configure();         
          
    // Add some log messages
    log.debug("This is a debug message");
    log.trace("This is a trace message");         
  }
}

Output
0 [main] DEBUG com.sourcetricks.log4j.Log4jTest  - This is a debug message
2 [main] TRACE com.sourcetricks.log4j.Log4jTest  - This is a trace message

With this basic examples let us jump into some terminology to understand Log4j better.

Log4J Terminology

Logger Hierarchy

In Log4j the loggers follow a hierarchy. There is always a root logger accessed using Logger.getRootLogger() and all other loggers are instantiated and accessed using Logger.getLogger(). Logger instances follow a named hierarchy. For example, com.sourcetricks is considered parent of com.sourcetricks.log4jtest.

Log Levels

Loggers can be assigned various levels including OFF, TRACE, DEBUG, INFO, WARN, ERROR, FATAL and ALL. By default if a logger is not assigned a level it inherits the level from the first non null level from the logger hierarchy towards the root logger.

Appenders

Appenders define the output destination for logs. Examples include console, file, syslog etc. Appenders also follow the logger hierarchy.

Layouts

Log4j allows the log output line to be customized as well. This is called layouts.
e.g) 0 [main] DEBUG com.sourcetricks.log4j.Log4jTest  - This is a debug message

Configuration

Log4j provides the capability and flexibility to fully customize the logging needs either via APIs, Java properties (key = value) format or using XML files. Normal convention to use configuration files instead of APIs to perform the Log4j customization.

With this basic introduction let us look at some more examples to understand better the various customization options.

Using Log4J PropertyConfigurator to log debug messages to the console

In this example we use a PropertyConfigurator and specify the properties file to log debug messages to the console. Additionally we use the layout customization.

package com.sourcetricks.log4j;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class Log4jTest {

    // Initialize logger for instance Log4jTest
    static Logger log  = Logger.getLogger(Log4jTest.class);
	
    public static void main (String[] args) {	
	// Property configurator
	PropertyConfigurator.configure("resources/log4j.console");		
		
	// Add some log messages
	log.debug("This is a debug message");
	log.trace("This is a trace message");
    }
}

Properties file
# Set root logger
log4j.rootLogger=DEBUG, console
 
# Add log messages to console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n

Output
2014-02-09 07:58:03 DEBUG com.sourcetricks.log4j.Log4jTest - This is a debug message

With this basic understanding now it is all about customizing the property files to meet our customization needs. Please refer to this article Log4j properties configuration examples on some sample Log4J property file examples.

Sunday, February 2, 2014

JAXB for XML handling

Java Architecture for XML Binding (JAXB) provides a fast and convenient way to bind XML schemas and Java representations. JAXB provides methods for reading XML documents into Java objects and writing Java objects into XML documents.

JAXB annotations are used for customizing Java program elements to XML mapping. Refer to this link for list of annotations supported.

In this example below we use JAXB to write an XML document from Java objects and to read an XML document into Java objects. 

Some of the annotations we use in this example.
  1. XmlRootElement - Maps a class or an enum type to an XML element.
  2. XmlElement - Maps a JavaBean property to a XML element derived from property name.
  3. XmlAttribute - Maps a JavaBean property to a XML attribute.
First we need to create the necessary Java objects to hold our data. We create a Book object and a Catalog object to hold bunch of books. We use XmlRootElement annotation to the class and XmlAttribute annotation to the id property. Other properties are interpreted by default as XmlElement.

package com.sourcetricks.jaxb;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="book")
public class Book {

 private String id;
 private String title;
 private String author;
 private String genre;
 private String price;
 private String description;
 
 @XmlAttribute(name="id")
 public String getId() {
  return id;
 }
 public String getTitle() {
  return title;
 }
 public String getAuthor() {
  return author;
 }
 public String getGenre() {
  return genre;
 }
 public String getPrice() {
  return price;
 }
 public String getDescription() {
  return description;
 }
 public void setId(String id) {
  this.id = id;
 } 
 public void setTitle(String title) {
  this.title = title;
 }
 public void setAuthor(String author) {
  this.author = author;
 }
 public void setGenre(String genre) {
  this.genre = genre;
 }
 public void setPrice(String price) {
  this.price = price;
 }
 public void setDescription(String description) {
  this.description = description;
 }
}

Next we create a catalog object that holds a list of books.

package com.sourcetricks.jaxb;

import java.util.ArrayList;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="catalog")
public class Catalog {

 @XmlElement(name="book")
 private ArrayList<Book> listOfBooks;
 
 public Catalog() {
  listOfBooks = new ArrayList<Book>();
 }
 
 public void addBook(Book book) {
  listOfBooks.add(book);
 }
 
 public void printBooks() {
  for ( Book b : listOfBooks ) {
   System.out.println(b.getId());
   System.out.println(b.getTitle());
   System.out.println(b.getAuthor());
   System.out.println(b.getGenre());
   System.out.println(b.getPrice());
  }
 }
}
Finally the test program which marshals and unmarshals the XML documents.
package com.sourcetricks.jaxb;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class JaxbTest {

 private void marshalTest() {
  // Create a catalog
  Catalog catalog = new Catalog();

  // Add some books
  Book book1 = new Book();
  book1.setId("100");
  book1.setTitle("XML Developer's Guide");
  book1.setAuthor("Gambardella, Matthew");
  book1.setGenre("Computer");
  book1.setPrice("44.95");
  book1.setDescription("An in-depth look at creating applications with XML");
  catalog.addBook(book1);

  // Marshal the catalog object into XML
  try {
   JAXBContext context = JAXBContext.newInstance(Catalog.class);
   Marshaller marshaller = context.createMarshaller();
   // Format the output
   marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
   System.out.println("------------- Marshal Test----------------------");
   marshaller.marshal(catalog, System.out);   
  } catch (JAXBException e) {
   e.printStackTrace();
  }
 }
 
 public void unmarshalTest() {
  FileReader reader = null;
  // Read an XML document and unmarshal into Java objects
  try {
   reader = new FileReader("resources/input.xml");  
   JAXBContext context = JAXBContext.newInstance(Catalog.class);
   Unmarshaller unmarshaller = context.createUnmarshaller();
   Catalog c = (Catalog) unmarshaller.unmarshal(reader);
   System.out.println("------------- Unmarshal Test----------------------");
   c.printBooks();
  } 
  catch ( FileNotFoundException e ) {
   e.printStackTrace();
  } 
  catch (JAXBException e) {
   e.printStackTrace();
  } 
  finally {
   if ( reader != null )
    try {
     reader.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
  }
 }

 public static void main(String[] args) {
  JaxbTest j = new JaxbTest();
  j.marshalTest();
  j.unmarshalTest();  
 }
}
Output
------------- Marshal Test----------------------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalog>
    <book id="100">
        <author>Gambardella, Matthew</author>
        <description>An in-depth look at creating applications with XML</description>
        <genre>Computer</genre>
        <price>44.95</price>
        <title>XML Developer's Guide</title>
    </book>
</catalog>
------------- Unmarshal Test----------------------
bk101
XML Developer's Guide
Gambardella, Matthew
Computer
44.95

Popular Posts

Powered by Blogger.

 

© 2013, 2014 Programming Tutorials by SourceTricks. All rights resevered. Designed by Templateism

Back To Top