Monday, April 19, 2010

Converting String instance variables of any given object to uppercase

In this post I will describe how to convert all the String members of an object into uppercase. The same can be done to convert to lowercase. Creating a method in a class (JavaBean) can also solve this purpose, but when the JavaBeans are already available then modifying each class is a tedious process. This was exactly the problem that I was facing. Then I though of using something similar to the 'copyProperties' method of the 'BeanUtils' class in Commons BeanUtils.


The Java Reflection API came to assistance. Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

The 'java.lang.reflect' package provides various classes and methods which can be used to deeply examine an object, find out its member variables and  methods, invoke its setter and getter methods and much more. The below code will show how you can use the Java Reflection API to access the setter and getter methods of an object of any type and convert all the member variables of type 'String' to uppercase.

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionUtil
{
    public static void printValues(Object obj)
    {
 Class c = obj.getClass();
 
 Field fields[] = c.getDeclaredFields();
 Method method;
 String gMethodName, sMethodName, value;

 try
 {
      for(Field f : fields)
     {
                if(f.getType().toString().contains("java.lang.String"))
  {
      gMethodName = "get" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1);
      method = c.getDeclaredMethod(gMethodName);
      value = (String) method.invoke(obj);
      System.out.println(f.getName() + ":" + f.getType() + ":" + value);
  }
   
     }
        }
 catch(Exception ex)
 {ex.printStackTrace();}
    }

    public static void convertToUpperCase(Object obj)  
    {
 Class c = obj.getClass();
 
 Field fields[] = c.getDeclaredFields();
 Method method;
 String gMethodName, sMethodName, value;

 try
 {
      for(Field f : fields)
     {
                if(f.getType().toString().contains("java.lang.String"))
  {
      gMethodName = "get" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1);
      method = c.getDeclaredMethod(gMethodName);
      value = (String) method.invoke(obj);
      value = value.toUpperCase();
      sMethodName = "set" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1);
      method = c.getDeclaredMethod(sMethodName, f.getType());
      method.invoke(obj, new Object [] {value});
  }
     }
        }
 catch(IllegalAccessException ex)
 {ex.printStackTrace();}
 catch(java.lang.reflect.InvocationTargetException ex)
 {ex.printStackTrace();}
 catch(java.lang.NoSuchMethodException ex)
 {ex.printStackTrace();}
    }

    public static void main(String... args)
    {
  Category category = new Category("abc", "cat name", null, "user", "code");
 System.out.println("\nCalling convertToUpperCase");
 ReflectionUtil.convertToUpperCase(category);
 System.out.println("\nCalling printValues");
 ReflectionUtil.printValues(category);
    }
}

For a detailed tutorial on Java Reflection API click here.

Friday, January 15, 2010

Creating a zip file

Creating a zip file in Java web application may appear to be a difficult task, but thanks to Java which comes bundled with many packages and classes which provide many useful utilities, tools and methods. One such package is the "java.util.zip" package which provides various classes and methods to manage zip files.

Following is an extract of code from a Servlet which can be customized and used to create zip files.


import java.util.zip.*;

// These are the files to include in the ZIP file
java.util.Set fileNames = new java.util.TreeSet () ; 

fileNames.add(csvFileName);
// add multiple files as above

/*
 * Creating a ZIP File
 */
     
  // Create a buffer for reading the files
  byte[] buf = new byte[1024];
  String outFilename="";
  fileName="";
  try 
  {
     // Create the ZIP file
     outFilename = getServletContext().getRealPath("/insurance") + "/" + "insurance.zip";
     ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(outFilename));
     
     // Compress the files
     for(String str : fileNames)
     {
         FileInputStream in = new FileInputStream(str);
    
         // Add ZIP entry to output stream.
         fileName = str;
         fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
         zipOut.putNextEntry(new ZipEntry(fileName));
     
         // Transfer bytes from the file to the ZIP file
         int len;
         while ((len = in.read(buf)) > 0) 
            zipOut.write(buf, 0, len);
  
         // Complete the entry
         zipOut.closeEntry();
         in.close();
     }
     
     // Complete the ZIP file
     zipOut.close();
  }
  catch(java.util.zip.ZipException ex)
  {
      System.out.println("InsuranceReportArtistWiseServ:ZipException:creating zip\n"+ex);
  }
  catch(IOException ex) 
  {
      System.out.println("InsuranceReportArtistWiseServ:IOException:creating zip\n"+ex);
  }

  /*
   * Clean up - zip file ready to download, now delete all csv files
   */
    boolean success=false;
    for(String str : fileNames)
    {
    success = (new java.io.File(str)).delete();
    }
Now the "insurace.zip" file is ready to be sent as a download to the user.

Sending a file as a download using Java

Many times it may be a requirement to send a file from a server to a user as a download which can be saved on the users machine. To send a file as a download to a user all you need is a Servlet and the file which will be sent to the user. Below is a sample code for the Servlet which will send a file as a download.

private static javax.servlet.ServletConfig config;

/* (non-Javadoc)
 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
 */
@Override
public void init(ServletConfig config) throws ServletException 
{
    // TODO Auto-generated method stub
    super.init(config);
    FileDownloadServ.config = config;
}

private void sendFile(String fileName, HttpServletRequest request, HttpServletResponse response)
{
  java.io.File f = null;
  String file;
  
  file = FileDownloadServ.config.getServletContext().getRealPath("/" + fileName);
  f = new java.io.File(file);

  int length = 0;
  javax.servlet.ServletOutputStream op=null; 
  try
  {
      op = response.getOutputStream();
  }
  catch(java.io.IOException ex)
  {
      System.out.println("IOException while opening the output stream\n"+ex);
  } 

  javax.servlet.ServletContext context  = getServletConfig().getServletContext();
  String mimetype = "application/octet-stream";
  response.setContentType(mimetype);
  response.setContentLength( (int)f.length() );

  response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"" );
  //
  //  Stream to the requester.
  //
  byte[] bbuf = new byte[1024];
  try
  {
     java.io.DataInputStream in = new java.io.DataInputStream(new java.io.FileInputStream(f));

     while ((in != null) && ((length = in.read(bbuf)) != -1))
     {
      op.write(bbuf,0,length);
     }

     in.close();
     op.flush();
     op.close();
  }
  catch(java.io.IOException ex)
  {
     System.out.println("IOException while reading file!\n"+ex);
  }
}     

The above method when called from a Servlet's doPost() or doGet() with fileName as parameter will sent the file to the user.

Tuesday, December 8, 2009

Converting between different date formats in Java

It is often required to convert date from one format to another, for example from java.sql.Date('yyyy-MM-dd') to java.util.Date ('dd/MM/yyyy'). I wrote a generic function to do the job, which will convert from any given date format to another specified format. The method does not checks if the format provided is correct or not nor it checks if the date is a valid date or not.

I wrote this method to read dates from the database and to convert it to another format. It is assumed that the dates in the table are valid. Below is the code for the method.

public static String convertDate(String date, String sourceFormat, String destinationFormat) throws java.text.ParseException
{
    String returnDate="";
  
    SimpleDateFormat formatter = new SimpleDateFormat(sourceFormat);
    Date date1 = formatter.parse(date);

    formatter = new SimpleDateFormat(destinationFormat);
    returnDate = formatter.format(date1);
 
    return returnDate;
}

Usage: String newDate = convertDate("2009-12-08", "yyyy-MM-dd", "dd/MM/yyyy")
Output: date in dd/MM/yyyy format - 08/12/2009

Monday, November 30, 2009

Accepting input from List based Forms using Struts

At times you may be required to get input from a list based form. A list based form can be well explained by taking an example of an object which may contain variable number of a list of items. An example being an invoice, which may contain 1 item, 2 items, 5 items or more. The number of items in an invoice are never fixed. You may write a JSP page and allow the user to add any number of items into a list and then finally submit the page to save the invoice.
A similar is the case with the items in a Gate Pass. A Gate Pass is a document which is produced every time whenever item(s) move out of an office. As an example consider the screenshot below:
gatePass 
In the above page (ActionForm) the user has an option to add as many items to the list as desired. Now if we map this page onto an ActionForm we need something in the ActionForm which can accept a list of items. The other fields will be mapped to String objects. An item consists of a code, description and quantity, which means an item is an object in itself, with the previously mentioned instance variables. Since, a Gate Pass will have a list of items you will need to map them to a Java Collections object which may be an ArrayList or a LinkedList. For this example, let us map the list of items on to a LinkedList object.
For the above example let us consider the following two classes:
import java.util.LinkedList; 
import Utility;
/** 
* @author Harkiran Singh 
* 
*/ 
public class GatePass implements java.io.Serializable 
{ 
    /** 
     * 
     */ 
    private static final long serialVersionUID = 1L; 
    private String gatePassNumber;
    private String financialYear; 
    private java.sql.Date gpDate = 
Utility.getSQLDateFromString(Utility.getDateToday()); 
    private String issuedTo; 
    private String gpType; 
    private String authorizedSignature; 
    private int isCanceled = 0; 
    private String cancelUser; 
    private LinkedList<GatePassItems&gt lstItems; 
    public GatePass() 
    { 
        lstItems = new LinkedList<GatePassItems&gt(); 
    }
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
.
(getter and setter methods for the instance variables)
}

/** 
* @author Harkiran Singh 
* 
*/ 
public class GatePassItems implements java.io.Serializable 
{ 
    /** 
     * 
     */ 
    private static final long serialVersionUID = 1L; 
    private String itemCode; 
    private String description; 
    private int quantity; 
    private String gatePassNo; 
    private java.sql.Date returnDate; 
    public GatePassItems(){} 
    public GatePassItems(String itemCode, String description, 
int quantity, String gatePassNumber) 
    { 
        this.itemCode = itemCode; 
        this.description = description; 
        this.quantity = quantity; 
        this.gatePassNo = gatePassNumber; 
    }
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
(getter and setter methods for the instance variables) 
}



Below is the ActionForm:


import java.util.LinkedList; 
import javax.servlet.http.HttpServletRequest; 
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping; 
/**
* @author Harkiran Singh
*
*/
public class GatePassForm extends ActionForm 
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String gatePassNumber;
    private String financialYear;
    private String gpDate=Utility.getDateToday();
    private String issuedTo;
    private String gpType;
    private String authorizedSignature;
    private String isCanceled = "0";
    private String cancelUser;
    private LinkedList<GatePassItems&gt; lstItems;
    private String description;
    private String quantity;
    private String itemCode;
    private String button;
    private String noOfItems;
    public GatePassForm()
    {
        lstItems = new LinkedList<GatePassItems&gt;();
    }

public GatePassItems getItem(int index)
{
    return lstItems.get(index);
}
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
. 
(getter and setter methods for the instance variables) 
}



The above method in the above ActionForm “getItem(int index)” is the key which will allow access to each item of the LinkedList.


Now, lets also look at the extract from the JSP file.


<c:set var="ctr" value="0"/>

    <table border="1" cellspacing="1" cellpadding="1" width="80%" align="center"&gt;


        <tr>


            <td width="5%" class="tablebgdark" align="right"&gt;<font class="fontwhite">S.No</font></td>

            <td width="20%" class="tablebgdark" align="center"&gt;<font class="fontwhite">Code</font></td>

            <td width="60%" class="tablebgdark" align="center"&gt;<font class="fontwhite">Description</font></td>

            <td width="10%" class="tablebgdark" align="center"&gt;<font class="fontwhite">Qty</font></td&gt;

            <td width="10%" class="tablebgdark">& </td>

        </tr>

        <logic:iterate id="item" name="GatePassForm" property="lstItems">

            <tr>

                <td align="right" class="tablebglight">

                    <c:set var="ctr" value="${ctr + 1}"/>

                    <font class="fontdark">${ctr }.</font>

                </td>

                <td>

                    <html:text name="item" property="itemCode" style="width:98%" indexed="true"&gt;</html:text>

                </td>

                <td>

                    <html:text name="item" property="description" style="width:98%" indexed="true"&gt;</html:text>

                    <html:hidden name="item" property="gatePassNo" value="${sessionScope.GatePassForm.gatePassNumber}" indexed="true"/>

                </td>

                <td>

                    <html:text name="item" property="quantity" style="text-align: right;width:98%" indexed="true"&gt;</html:text>

                </td>

                <td class="tablebglight">

                    <font class="fontdark">

                        <html:link page="/switch.action?prefix=/views/gatepass&&&page=/DeleteGatePassItem.action?index=${ctr-1}">Delete</html:link>

                    </font>

                </td>

            </tr>

        </logic:iterate>

        <tr>

            <td colspan="5" class="tablebgdark"><font class="fontwhite">New Item</font&gt;</td>

        </tr>

        <tr>

            <td class="tablebglight">&nbsp;</td>

            <td class="tablebglight">

                <html:text property="itemCode" style="width:98%" value="">&lt;/html:text>

            </td>

            <td class="tablebglight">

                <html:text property="description" style="width:98%" value="">&lt;/html:text>

            </td>

            <td class="tablebglight">

                <html:text property="quantity" style="text-align: right;width:98%" value="">&lt;/html:text>

                <html:hidden property="noOfItems" value="${ctr }"/>

            </td>

            <td class="tablebglight">&nbsp;</td>

        </tr>

        <tr>

            <td class="tablebglight">

                <html:submit property="button">Add Item</html:submit>

            </td>

            <td class="tablebglight">&nbsp;</td>

            <td class="tablebglight">&nbsp;</td>

            <td class="tablebglight">&nbsp;</td>

            <td class="tablebglight">&nbsp;</td>

        </tr>    
    </table>

The above JSP code in the iteration will be translated to HTML code which will access the LinkedList objects using the “getItem()” method.

The below line:

<html:text name="item" property="description" style="width:98%" indexed="true"&gt;</html:text> 

will get translated into following HTML:

<input type=”text” name=”item[0].description” >

and so on.

This will call the method “lstItems.getItems(0).getDescription()”,

“lstItems.getItem(0).setDescription(…)” and so on.

You will need to save the ActionForm in the session scope so that the previously entered objects are available until the form is submitted to save the Gate Pass in the database.

Also, you will need to add the code for adding the item into the LinkedList in the appropriate Action class which handles the form submission. Your Action class may look like:

public class AddGatePassItemAction extends Action 
{

 /* (non-Javadoc)
  * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
  */
 @Override
 public ActionForward execute(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception 
       {
    // TODO Auto-generated method stub
    
    GatePassForm gpForm = (GatePassForm) form;
  
    String description, quantity, gatePassNumber, itemCode;
    LinkedList lstItems = gpForm.getLstItems();
  
    description = gpForm.getDescription();
    quantity = gpForm.getQuantity();
    gatePassNumber = gpForm.getGatePassNumber();
    itemCode = gpForm.getItemCode();
  
    int qty = Integer.parseInt(quantity);
    GatePassItems item = new GatePassItems(itemCode, description, qty, gatePassNumber);
    
    lstItems.add(item);
    gpForm.setLstItems(lstItems);
   
    request.getSession().setAttribute("GatePassForm", gpForm);
  
    return mapping.findForward("success");
      }
}

With all the code and configuration entries in right place you will get a dynamically created LinkedList in your JSP page.