Sunday, November 12, 2006

use ListDataSource to easily pass object to JasperReports

Nowadays OR mapping framework and web framework are widely used in application, most of them use value objects go through entire transaction life cycle. But most of the applications also have report requirements, one of the most popular report engine framework is JasperReports.
If the same value objects can pass into report engine without having to transfer them or query database again to make another java type object, it will make the transaction more neater and easier to maintain.

Here is my implementation of JRDataSource, it is called ListDataSource, you just have to pass into java.util.List of value object(java.lang.Object) or implementation of java.util.Map.

Below are the code:

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

import org.apache.commons.beanutils.MethodUtils;

/**
 * @author Matt Jiang (matt.jiang@gmail.com)
 * @version 1.0
 */
public class ListDataSource implements JRDataSource {

  private List records = null;
  private Iterator iterator = null;
  private Object currentRow = null;
  private boolean disableReflection = false;
  
  public ListDataSource(List records, boolean disableReflection) {
    
    this.disableReflection = disableReflection;
    this.records = records;
    if (records != null)
      this.iterator = records.iterator();
  }
  
  public ListDataSource(List records) {
    
    this(records, false);
  }
  
  /**
   * cursor switch to next record
   */
  public boolean next() throws JRException {

    boolean hasNext = false;
    
    if (iterator != null) {
      hasNext = iterator.hasNext();
      if (hasNext)
        currentRow = iterator.next();
    }
    
    return hasNext;
  }

  /**
   * fieldName is defined in JasperReports, it will used as a key of Map or be transfered to getter method 
   * to retrieve value by java reflection. 
   */
  public Object getFieldValue(JRField jrField) throws JRException {

    String fieldName = jrField.getName();
    String methodName = makeGetter(fieldName);
    Object fieldValue;
    
    if (currentRow instanceof Map)
      fieldValue = retrieveValueFromMap((Map)currentRow, fieldName);
    else {
      if (disableReflection)
        fieldValue = currentRow;
      else
        fieldValue = retrieveValueFromReflection(currentRow, fieldName);
    }
    
    return fieldValue;
  }
  
  private Object retrieveValueFromMap(Map currentRow, String fieldName) {
    
    return currentRow.get(fieldName);
  }
  
  private Object retrieveValueFromReflection(Object currentRow, String fieldName) {
    
    Object fieldValue = null;
    try {
      fieldValue = MethodUtils.invokeMethod(currentRow, makeGetter(fieldName), null);
    } catch (Exception e) {
      e.printStackTrace();
      ; // ignore this exception on purpose
    }
    return fieldValue;
  }
  
  private String makeGetter(String fieldName) {
    
    StringBuffer getter = new StringBuffer();
    getter.append("get").append(fieldName.substring(0, 1).toUpperCase()).append(fieldName.substring(1));
    return getter.toString();
  }

  public String size() {
    
    String size = "0";
    if (records != null) {
      size = String.valueOf(records.size());
    }
    
    return size;
  }
}

1 comment:

Anonymous said...

Thanks for article.
I'll try to integrate it into my application.

I lost all day trying to find a way integrate Jasper Reports into A web application.

Best Regards,
Paul.