Skip to content
November 23, 2011

Easy xml parsing using java annotatoins

Java 1.5 is shipped with an annotation API (javax.xml.bind.annotation package) for Xml processing. With this API you don’t have to write code to traverse and parse xml documents. You just need to annotate your business classes with relevant xml tags. Once java classes are properly annotated and a target xml file is provided; the java xml parser populate objects from annotated classes which are injected with relevant xml values.

Here’s a simple example.

A Simple Example

Look at the following xml document that defines a shopping cart with an apple inside.

<shopping-cart name=”myShoppingCart” active=”true”>

      <apple price=”12″/>

</shopping-cart>

Listing 1

 

Let’s try to develop an xml parser for above Document 1 using java annotations. The source code of the ShoppingCart.java and Apple.java classes would be,

@XmlAccessorType (XmlAccessType.FIELD)

@XmlRootElement (name = “test-unit”)

public class ShoppingCart {

     

      @XmlAttribute (name = “name”)

      private String name;

 

@XmlAttribute (name = “active”)

      private boolean isActive;

@XmlElementRef

      private Apple apple;

      …

}


@XmlRootElement (name = “test-case”)

public class Apple {

      @XmlAttribute (name = “price”)

      private double price;

…    

}

Listing 2

Annotations definitions

Followings are the most commonly used annotations for xml processing.

@XmlRootElement

Used at class level to annotate the class with the corresponding xml tag.

@XmlAccessorType

Used at class level. This annotation defines whether to use the field access or the property access to inject the xml elements.

@XmlElement

Used at field / property level. This one defines the mapping xml tag for a property of a java class. This element provides basic primitive data conversions (using String constructors of primitive data types) like String to int, String to boolean etc.

@XmlElements

This element is a container for multiple @XmlElement annotations. Used when a single field on a class is mapped to multiple xml tags.

@XmlElementRef

Defines a dynamic association between a java property and xml element. So the actual xml tag to java field mapping is dynamically derived at the runtime.

Complete java doc is available here http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/package-summary.html.

A complete example

Let’s consider a shopping cart with a lot of fruits.

<shopping-cart name=”myShoppingCart” active=”true”>

      <apple price=”12″/>

<orange price=”12″/>

</shopping-cart>

Listing 3

Instead of keeping a single Apple reference inside the shopping cart we would like to keep a reference like List<Fruit> so that we can put any number of Fruits to the shopping cart. So the new source code for shopping cart is,

@XmlAccessorType (XmlAccessType.FIELD)

@XmlRootElement (name = “test-unit”)

public class ShoppingCart {

     

      @XmlAttribute (name = “name”)

      private String name;

 

@XmlAttribute (name = “active”)

      private boolean isActive;

     

@XmlElementRef

      private List<Fruit> fruits;  

      …

}

Listing 4

 

The implementation of Fruit, Apple and Orange classes are as follows.

//no XmlRoot element is required

public abstract class Fruit {

      @XmlAttribute (name = “price”)

      private double price;

…    

}

@XmlRootElement (name = “apple”)

public class Apple extends Fruit{        

…    

}

@XmlRootElement (name = “orange”)

public class Orange {

…    

}

Listing 5

 

When the Java xml parser encounters a <shopping-cart> tag, it will populate an instance of the ShoppingCart class. Here we have mapped the name and isActive java properties to the xml tags name and active using @XmlAttribute annotation. So the xml parser will use this mapping to inject values to the ShoppingCart instance.

Next, the xml parser will read the <apple … tag. After a no direct mapping is detected on initial lookup, it will look up for @XmlElementRef elements (Fruit class in this case). It will traverse down the class hierarchy to find a class annotated with “apple” tag (Apple class in this case) and will create an instance of that class and insert it to the Fruits list. (Same for the <orange> tag)

November 25, 2011

Whitespace collapse

November 25, 2011

How to implement a correct sax xml parser

Hi folks,

I had been working with xml recently and case across the SAX parser. According to the java doc the “characters” method of the handler may send you discontinues chunks of data. For most of the time this doesn’t happen. But it happens. It happened to me. Depending on the contents of you xml document. So I have implemented a SAX parser with an internal buffer which caches all the incoming data to the characters method and process the whole chunk of data in the endElement method. This method ensures correct behavior of SAX parser. So here’s an example.

 

public abstract class SampleSAXParser extends HandlerBase {

private StringBuilder recievedData;

public EspmlCardProfileBatchloadHandler(Tracer pTracer,
ReportManager pReportMgr, EspmlElementFieldsValidator validator) {
recievedData = new StringBuilder();// initializing the buffer for input
}

// catch exceptions
@Override
public void startElement(String uri, String name, String qName,
Attributes attrs) throws SAXException {

}

// catch exceptions
/* to do implement BadParameterFormatExceptionRca exceptions */
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String value = String.valueOf(ch, start, length).trim();
recievedData.append(value); //append input data to buffer

}

private void handleBufferedData() throws Exception {
if (recievedData.length() > 0) {
String value = recievedData.toString();
processRecievedData(value); //process data
recievedData = new StringBuilder(); //create an empty buffer for next read
}
}

// catch exceptions
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
handleBufferedData(); //process element contents
}
}

 

 

Hope this helps. Thank you.

 

 

Regards,

Lasith.

November 23, 2011

Java FilenameFilter example – How to search a directory using java

Hi folks,

Following program filters the all the .xml files inside of the “d:/test_folder” directory. Please note that I have provided an inline implementation for the FileNameFilter, which acts as the searching criteria.

File dirFile = new File(“D:/test_folder”);
File[] files = dirFile.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(“.xml”);
}
});

//iterating the sub xml files list
for (File localFile : files) {
//what ever you want to do

}

Hope this helps.

Thank you.

Regards,

Lasith.

February 23, 2011

Run quartz job at a given set of clock times, every day

Hi folks,

We have an applications which uses quartz for job scheduling. I had to implement this simple behavior. I needed to run a particular job at given set of clock times say (10AM,11.30AM, 1PM, 5PM) every day. I’m familiar with quartz simple and cron triggers. But I found out that either of the triggers are unable to implement this behavior. So I decided to implement a new quartz trigger to support this requirement.(only :D )

Here goes the source code.

 

Source code of the TriggeringTimesCollection class. This is an utility class for the CustomTrigger.

package trigger;
import java.util.*;

import java.text.SimpleDateFormat;
import org.apache.log4j.Logger;

public class TriggeringTimesCollection {

private static final String DATES_DELIMITER = “,”;

public static Logger logger = Logger.getLogger(TriggeringTimesCollection.class);

private List<Date> triggerTimes;

private int currentPoss;
public static TriggeringTimesCollection createInstance(String datesList) {

StringTokenizer st = new StringTokenizer(datesList, DATES_DELIMITER);

List<Date> triggerTimesList = new ArrayList<Date>();

SimpleDateFormat format = new SimpleDateFormat(“HH/mm/ss”);

Date tmpDate;

while (st.hasMoreTokens()) {

try {

tmpDate = format.parse(st.nextToken());

triggerTimesList.add(tmpDate);

} catch (Exception e) {

logger.error(e.getMessage(), e);

continue;

}

}

Collections.sort(triggerTimesList);

return new TriggeringTimesCollection(triggerTimesList, -1);
}

public TriggeringTimesCollection(List<Date> triggerTimes, int currentPoss) {

this.triggerTimes = triggerTimes;

this.currentPoss = currentPoss;

}
public Date getTimeAfter(Date date) {

Calendar calendar = Calendar.getInstance();

calendar.setTime(date);

Calendar cal2 = (Calendar) calendar.clone();

Calendar cal3 = (Calendar) calendar.clone();

Date result = null;

cal2.set(Calendar.MILLISECOND, 0);

for (Date tmpDate : triggerTimes) {

cal3.setTime(tmpDate);

cal2.set(Calendar.YEAR, cal3.get(Calendar.YEAR));

cal2.set(Calendar.MONTH, cal3.get(Calendar.MONTH));          //compare regardless of the date

cal2.set(Calendar.DATE, cal3.get(Calendar.DATE));

if (cal2.getTime().before(tmpDate)) {

result = tmpDate;

break;

}        }

 

if (result == null) { // get first start of next date

result = triggerTimes.get(0);

calendar.setTimeInMillis(calendar.getTimeInMillis() + 24 * 60 * 60 * 1000);//switch to next day

}

cal2.setTime(result);

calendar.set(Calendar.HOUR_OF_DAY, cal2.get(Calendar.HOUR_OF_DAY));

calendar.set(Calendar.MINUTE, cal2.get(Calendar.MINUTE));

calendar.set(Calendar.SECOND, cal2.get(Calendar.SECOND));

result = calendar.getTime();
return result;

}

public Date getTimeBefore(Date date) {

Calendar calendar = Calendar.getInstance();

calendar.setTime(date);

Calendar cal2 = (Calendar) calendar.clone();

Calendar cal3 = (Calendar) calendar.clone();

Date result = null;

cal2.set(Calendar.MILLISECOND, 0);

for (Date tmpDate : triggerTimes) {

cal3.setTime(tmpDate);

cal2.set(Calendar.YEAR, cal3.get(Calendar.YEAR));

cal2.set(Calendar.MONTH, cal3.get(Calendar.MONTH));          //compare regardless of the date

cal2.set(Calendar.DATE, cal3.get(Calendar.DATE));

 

if (cal2.getTime().before(tmpDate)) {

break;

} else {                result = tmpDate;            }        }

if (result == null) { // get first start of prevous date

cal3.setTime(triggerTimes.get(triggerTimes.size() – 1));

cal2.set(Calendar.YEAR, cal3.get(Calendar.YEAR));

cal2.set(Calendar.MONTH, cal3.get(Calendar.MONTH));          //compare regardless of the date

cal2.set(Calendar.DATE, cal3.get(Calendar.DATE));

calendar.setTimeInMillis(calendar.getTimeInMillis() – 24 * 60 * 60 * 1000);//switch to next day

}

cal2.setTime(result);

calendar.set(Calendar.HOUR, cal2.get(Calendar.HOUR));        calendar.set(Calendar.MINUTE, cal2.get(Calendar.MINUTE));        calendar.set(Calendar.SECOND, cal2.get(Calendar.SECOND));

result = calendar.getTime();

return result;

}

}

 

 

The source code for the CustomTrigger class.

package trigger;
import org.quartz.*;
import java.util.Date;

import java.util.List;

public class CustomTrigger extends CronTrigger {

private TriggeringTimesCollection triggeringTimesCollection;
public CustomTrigger(String triggerName, String jobName, String triggerDates){

super(triggerName, jobName);

triggeringTimesCollection = TriggeringTimesCollection.createInstance(triggerDates);

}

 

protected Date getTimeAfter(Date afterTime) {

return (triggeringTimesCollection == null) ? null : triggeringTimesCollection.getTimeAfter(afterTime);

}

protected Date getTimeBefore(Date beforeTime){

return (triggeringTimesCollection == null) ? null : triggeringTimesCollection.getTimeBefore(beforeTime);

}

}

 

Here CustomTrigger is the actual trigger and TriggeringTimesCollection is an utility class.

 

 

Thanks.

 

Regards,

Lasith.

 

February 21, 2011

JMS Exception listeners (How and Why)

Hi folks,

Exception listeners are used to deliver  connection related exceptions to the program. It is important to understand that all kind of exceptions will not be delivered to exception listeners. Only the exceptions no where else to throw :) .

The implementation is simple. Sub class the javax.jms.ExceptionListener interface.

Implement the onException method.

Register the exception listener to JMS connection object.

Sample code is provided below.

public class JMSExceptionListener implements ExceptionListener {
JMSConnector jmsConnection;
public JMSExceptionListener(JMSConnection jmsConnecion) {

this.jmsConnection = jmsConnection;

}

public void onException(JMSException e)

{        e.printStackTrace();

jmsConnection.restart();

}

}

Here I restart the JMS connection in case of an exception. This is considered as a best practice since most of the exceptions delivered in to the Exception Listeners are connections related Exceptions.

Registering the Exception listener on jms connection.

queueConnection = queueConnectionFactory.createQueueConnection();

queueConnection.setExceptionListener(new JMSExceptionListener(jmsConnection));

queueConnection.start();

Regards,

Lasith.

September 7, 2010

Windows Batch file exists after maven command completes

Hi folks,

It’s been while since my last post. However here we go again.

Recently I have involved with some  java projects. Here we used Apache Maven build tool to build and deploy the project. To avoid the repetition of typing maven build command (a lengthy one with custom build profiles) several times a day, I decided to create the following batch file.

echo OFF

cd “my_project_folder”

mvn clean install

echo ON

pause

Everything went fine with above set of commands excepts the pause command never executes. So I could never have a good look at the maven build results. After some research I found the solution.

mvn itself is a batch file. So with execution of mvn clean install line, my original batch file delegates the control to the maven batch file. But after the maven execution completes it never returns the control to the original batch file. So any command after the mvn clean install line never executes.

In order to return the control to the calling batch file you need to use it as

call mvn clean install

Solved.

Regs,

Lasith.

December 2, 2009

Java entity bean deployment failed in IBM Web sphere Application server

Hi folks,

Few days ago I was working in a J2EE application developed using EJB 2.0. After completing some development I have deployed the application in JBoss application server and tested it. It worked fine. But when I tried to deploy it on Web Sphere application server, the development failed. The issue was at an entity bean method. I had a getter and a setter for a particular column of the relevent DB table. Let’s say the attribute was Index_No. So my getter and setter was like,

public  int getIndex_No();

public void setIndex_No(java.lang.Integer index);

I think you have noticed the issue. Setter sets an Integer object and getter returns an int primitive value. This was quite easy to track. But it was really weired. (Jboss is ok with it) So I learnt that when you working with web sphere, better to write 100% specification compliance source code.

Thanks.

Regads,

Lasith.

October 24, 2009

java.lang.ClassCastException after the JNDI lookup of javax.mail.session

This issue is due to a mismatch of jar files. The jboss lib folder $JBOSS_HOME$/server/default/lib/ contains the mail.jar file. (Java Mail library) And as usual  you may have included the Java Mail Library jar in your deployed project. (.war or .ear). Both the libraries has the javax.mail.Session class. So the class loader will load the both as two different classes. This originates the issue.

javax.mail.Session session = (javax.mail.Session) context.lookup(“)

Here you going to load the java mail session from a jndi lookup. So the contex.lookup(“..”) returns a javax.mail.Session_JBOSS object. Now you try to cast it. But unfortunately the javax.mail.Session class used in your code is loaded as a different class (javax.mail.Session_USER). So java throws an ClassCastException.

Remove the java mail jar file from the lib folder of your application. It will work fine.

I have experienced the above issue for several other libraries too (log4j).

Hope this will help.

Rgs,

Lasith.

September 16, 2009

Failed to initialize the ORB Exception

Recently I was working with some EJBs. I use Web Sphere 6.1 as the EJB container. And in the lookup jndi method I encountered an exception “Failed to initialize the ORB Exception”. My application also has a
Jboss version also and it worked fine. So after some searchings I have found that I have to add some VM parameters to do the work. So addition of following parameters solved the problem.

org.omg.CORBA.ORBClass=com.ibm.CORBA.iiop.ORB
org.omg.CORBA.ORBSingletonClass=com.ibm.rmi.corba.ORBSingleton
javax.rmi.CORBA.StubClass=com.ibm.rmi.javax.rmi.CORBA.StubDelegateImpl
javax.rmi.CORBA.PortableRemoteObjectClass=com.ibm.rmi.javax.rmi.PortableRemoteObject
javax.rmi.CORBA.UtilClass=com.ibm.ws.orb.WSUtilDelegateImpl

My IDE was JIdea. When I tried to run the application in JIdea, I have encounterd the same problem gin. I tried adding VM parametrs in Edit Configuration window. But it never worked. I still looking for a solution.
But as a temporary fix, I used the IBM JVM provided with the web sphere installation and it solved the problem for now.

Follow

Get every new post delivered to your Inbox.