Sunday, December 25, 2011

Struts2 json plugin - Action class public method names with "get" prefix.

I recently figured out this, what I am going to explain you, and it can make a huge impact for an application. I am using struts 2 JSON plugin for an AJAX invocations to action class methods and to send a JSON response. Struts 2 JSON plugin serializes all the bean properties when sending a JSON response to the browser. Sometime, you may not know that, While serialization process, it invokes all the public method which are having “get” prefix in their method names. If we really don’t know about this, it can make a significant impact to our application’s performance and generates exceptions which are hard to figure out. I will explain how this can impact for an application. Look into the following two methods which are defined in ‘DepartmentAction’ class. Those tow method returns JSON response to the browser.

public String getAllEmployees() throws Exception {
    List<Employee> employees = departmentService.getDepartmentEmployees();
    setEmployees(employees);
    return JSON;
}
public String getActiveDepartmentsByLocationId() throws Exception { 
    List<Department> departmetns = departmentService.getActiveDepartmentsByLocationId(locationId);
    setDepartments(departmetns); 
    return JSON;
} 
Normally, When you want to get the list of departments for a given location id, you will invoke the method ‘getActiveDepartmentsByLocationId’ method with an AJAX request. When the function returns the JSON response, it serializes action class bean properties which causes to invoke "getAllEmployees" method also. That means, it invoke the relevant service method from “getAllEmployees” method also. But you only need to get the list of departments for a given location id. Can you guess the impact for the application?

If you put a break point in “getAllEmployees” method while invoking “getActiveDepartmentsByLocationId” method, You will understand this behavior. Normally, developers are used to give “get” prefix for action class methods. If you use struts2 JSON plugin, make sure not to use “get” prefix for public method names which are resulting JSON response. You can use “find” prefix instead.

Thursday, December 8, 2011

Java sorting function with Generics and Reflection

Fed up with writing sorting function every time??. This post will be a great relief for you.I am going to explain, How to write a java class which can be used to sort any type of java object collection in any field in any order. Thanks for introducing java 5 Generics and Reflection in Java.

/**
 * 
 */
package com.shims.support;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author Semika Siriwardana
 *
 */
public class SHIMSSoringSupport<T> {

 private List<T> objectList;
 private String sortField = null;
 private String sortOrder = null;
 private static final String ASC = "asc";
 /**
  * @param 
  * 
  *   objectList 
  *    The list to be sorted
  * @param sortField
  *    The field name in which list to be sorted
  * 
  * @param sortOrder
  *    Sorting order.Either assending or decending. 
  */
 public SHIMSSoringSupport(List<T> objectList, String sortField,
   String sortOrder) {
   super();
   this.objectList = objectList;
   this.sortField = sortField;
   this.sortOrder = sortOrder;
 }
 
 /**
  * Perform soring
  * @param aClass
  * @throws Exception
  */
 public void sort(final Class aClass) throws Exception {
  
    final String _sortField = this.sortField;
    final String _sortOrder = this.sortOrder;
  
    Collections.sort(this.objectList, new Comparator<T>() {

    @Override
    public int compare(T o1, T o2) {
    
    try {
        Field sortField = aClass.getDeclaredField(_sortField);
        sortField.setAccessible(true);
     
        Object val1 = sortField.get(o1); 
        Object val2 = sortField.get(o2);
     
        if (val1 instanceof String && val2 instanceof String) {                                            
           if (ASC.equals(_sortOrder)){ //String field
               return ((String) val1).compareTo((String)val2);
           } else {
               return ((String) val2).compareTo((String)val1);
           }
        } else { //Numeric field  
           Number num1 = (Number)val1;
           Number num2 = (Number)val2;
      
           if (ASC.equals(_sortOrder)) {
               if (num1.floatValue() > num2.floatValue())  {
                  return 1;
               } else {
                  return -1;
               }
           } else {
                if (num2.floatValue() > num1.floatValue())  {
                    return 1;
                } else {
                    return -1;
                }
           }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } 
    return 0;
   }
  });
 }
}


Next, I will explain how to use above class to sort a list of objects. As You can see in the code, when instantiating class instance, You have to pass three constructor arguments into it.

objectList  - List of objects that are needed to get sorted.
sortField   - The field in which, You want to sort the collection.
sortOrder - The sorting order.This should be either 'asc' or 'desc'.

Following code shows, How to instantiate a class instance and invoke the sorting.

Think, You have a list of 'Employee' objects to sort.

List<Employee> empList = employeService.getAllEmployees(); 
   
SHIMSSoringSupport<Employee> soringSpt 
     = new SHIMSSoringSupport<Employee>(empList, "name", "asc");
soringSpt.sort(Employee.class);

The above code will sort the employee list by it's 'name' field in ascending order.

Wednesday, October 12, 2011

Javascript string concatenation vs array.join()

When we are implementing some dynamic web contents, most of the time, We have used to create string HTML and set it as an inner HTML of particular container elements. Normally, We use '+' operator to concatenate strings as follows.

var html = "<table><tr><td>";
html += "This is td contents";
html += "</td></tr></table>";

I will suggest you a more faster method to do the same. For this, I am going to keep every string as an element of javascript array and finally join them to create a one string.

var sb = []; //create empty javascript array
sb[sb.length] = "<table><tr><td>";
sb[sb.length] = "This is td contents";
sb[sb.length] = "</td></tr></table>";
Now By simply  concatenating them all together with a separator between them, You can get a one string as follows.The default separator is ','. To join without separation, use an empty string as the separator.
var html = sb.join("");

If you are assembling a string from a large number of pieces, it is usually faster to put the pieces into an array and join them than it is to concatenate the pieces with the + operator.

Sunday, September 18, 2011

How to change SVN user in eclipse

When we connect to a SVN repository, we should provide username and password. Most of the time, We have used to set these credentials saved in a particular computer to prevent prompting for these credentials for subsequent synchronization with repository every time. Then for every workspace, eclipse will get these as SVN credential with out asking from us.

How can we reset these credentials to a another user account?

Go to this location in your computer file system.

C:\Documents and Settings\<User>\Application Data\Subversion\auth\svn.simple

Delete the file inside "svn.simple" folder, restart the eclipse and try to synchronize with repository again. You will be prompted for user name and password which was missing for long time in your computer.

I will update for linux soon. 

Sunday, September 11, 2011

How to Use Hibernate for Composite Ids with association mappings

Recently, We faced a tricky situation with hibernate association mapping with a composite id field. We needed to have bidirectional association with one-to-may and many-to-one.Our tow tables was "REPORT" and "REPORT_SUMMARY" which has one-to-many relationship from REPORT to REPORT_SUMMARY and many-to-one relationship from REPORT_SUMMARY to REPORT table. The primary key of REPORT_SUMMARY table is defined as a composite primary key which consists of auto increment id field and the primary key of REPORT table.
CREATE TABLE REPORT (
     ID INT(10) NOT NULL AUTO_INCREMENT,
     NAME VARCHAR(45) NOT NULL,
     PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE REPORT_SUMMARY (
   ID INT(10) NOT NULL AUTO_INCREMENT,
   NAME VARCHAR(45) NOT NULL,
   RPT_ID INT(10) NOT NULL,
   PRIMARY KEY (`ID`,`RPT_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

The hibernate entity classes are as fallows.

Report.java
package com.semika.autoac.entities;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Report implements Serializable{

    private static final long serialVersionUID = 9146156921169669644L;

    private Integer id;
    private String name;
    private Set<ReportSummary> reportSummaryList  = new HashSet<ReportSummary>();
    
    public Integer getId() {
         return id;
    }
    public void setId(Integer id) {
         this.id = id;
    }
    public String getName() {
         return name;
    }
    public void setName(String name) {
         this.name = name;
    }
    public Set<ReportSummary> getReportSummaryList() {
         return reportSummaryList;
    }
    public void setReportSummaryList(Set<ReportSummary> reportSummaryList) {
         this.reportSummaryList = reportSummaryList;
    }
}

ReportSummary.java
package com.semika.autoac.entities;

import java.io.Serializable;
public class ReportSummary implements Serializable {

private static final long serialVersionUID = 8052962961003467437L;

private ReportSummaryId id;
private String name;

public ReportSummaryId getId() {
    return id;
}
public void setId(ReportSummaryId id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    ReportSummary other = (ReportSummary) obj;
    if (id == null) {
       if (other.id != null)
          return false;
       } else if (!id.equals(other.id))
          return false;
    if (name == null) {
       if (other.name != null)
          return false;
       } else if (!name.equals(other.name))
          return false;

   return true;
  }
}

ReportSummaryId.java
package com.semika.autoac.entities;

import java.io.Serializable;

public class ReportSummaryId implements Serializable{

private static final long serialVersionUID = 6911616314813390449L;

private Integer id;
private Report report;

public Integer getId() {
   return id;
}
public void setId(Integer id) {
   this.id = id;
}
public Report getReport() {
   return report;
}
public void setReport(Report report) {
   this.report = report;
}
@Override
public int hashCode() {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((id == null) ? 0 : id.hashCode());
   result = prime * result + ((report == null) ? 0 : report.hashCode());
   return result;
}
@Override
public boolean equals(Object obj) {
   if (this == obj)
      return true;
   if (obj == null)
      return false;
   if (getClass() != obj.getClass())
      return false;
   ReportSummaryId other = (ReportSummaryId) obj;
   if (id == null) {
      if (other.id != null)
         return false;
      } else if (!id.equals(other.id))
         return false;
   if (report == null) {
      if (other.report != null)
         return false;
      } else if (!report.equals(other.report))
         return false;

   return true;
  }
}
Report object has a collection of ReportSummary objects and ReportSummaryId has a reference to Report object. The most important part of this implementation is hibernate mapping files.
Report.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.semika.autoac.entities.Report" table="REPORT" >
         <id name="id" type="int" column="id" >
                 <generator class="native"/>
         </id>
         <property name="name">
               <column name="NAME" />
         </property>
         <set name="reportSummaryList" table="REPORT_SUMMARY" cascade="all" inverse="true">
             <key column="RPT_ID" not-null="true"></key>
             <one-to-many class="com.semika.autoac.entities.ReportSummary"/>
         </set>
     </class>
</hibernate-mapping>
ReportSummary.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.semika.autoac.entities.ReportSummary" table="REPORT_SUMMARY" >
        <composite-id name="id" class="com.semika.autoac.entities.ReportSummaryId">
             <key-property name="id" column="ID"></key-property>
             <key-many-to-one name="report" 
                              class="com.semika.autoac.entities.Report"
                              column="RPT_ID"</key-many-to-one>
        </composite-id>
        <property name="name">
             <column name="NAME" />
        </property>
    </class>
</hibernate-mapping>

Saturday, July 2, 2011

How to delete child elements in Parent/Child relationship - JPA

Orphans are the elements removed from a child collection in a parent/child relation ship. If You expect the deletions of child records from the database with by removing child elements from the child collection or with the deletion of parent record in a parent/child relationship with javax.persistence.CascadeType.All , it will not delete the child records from the database. But simple value typed child elements like a collection of strings, will be removed with the removal of parent object or with removal of elements from the child collection. When the parent is saved, the value-typed child objects are saved as well, when the parent is deleted, the children will be deleted. 

If the child objects being entities, not value-types, those have their own life cycle, like "Items" in a "Order". For this kind of scenario, If You want to delete child records from the database with the removal of child elements from the child collection or with the deletion of parent record, you will have to use
org.hibernate.annotations.CascadeType.DELETE_ORPHAN

public class Department {

    @OneToMany(cascade = {javax.persistence.CascadeType.ALL})
    List<Location> locations;

    @OneToMany(cascade = {CascadeType.ALL})
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)   
    List<Employee> employees;
}


Since "Location" is a simple value typed objects, javax.persistence.CascadeType.ALL will perfectly work when deleting orphans. But "Employee" is not a simple value typed objects. So We have to use hibernate's @Cascade annotation with value org.hibernate.annotations.CascadeType.DELETE_ORPHAN in order to remove orphans with removal of parent.

  • It doesn't usually make sense to enable cascade on a <many-to-one> or <many-to-many> association. Cascade is often useful for <one-to-one> and <one-to-many> associations.
  • If the child object's lifespan is bounded by the lifespan of the of the parent object make it a lifecycle object by specifying cascade="all,delete-orphan"
Share

Widgets