Tuesday 13 July 2010

A simple example of Java Reflection API

Java reflection API allows us to inspect classes on runtime. This is a very powerful tool but it's also very bad on performance. I use that technique on class converting. Suppose you have an entity you named User, and you don't want to serialize it to the client layer. You have to create a serializable class that has all the attributes you want to send back to the client and fill it with the entity content. This is a very good work for reflection.

I faced this problem on a project and I made a utility class to help resolve that. This is a very basic approach to a real solution but it works for me.

Let's see some code:

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.jflow.entities.GenericEntity;
import com.jflow.exceptions.EWConversionException;

public class ReflectionUtil {

    private static String capitalize(String s) {
        if (s.length() == 0) return s;
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
    
 public static <T> T convertClass(GenericEntity source, Class<T> destinationClass) throws EWConversionException {
  T desteny = null;
  try {
   if (source == null) {
    return desteny;
   }
   
   desteny = destinationClass.newInstance();
   Class<?> sourceClass = source.getClass();
         
         Field destFieldList[] = destinationClass.getDeclaredFields();
   for (Field field : destFieldList) {
    String name = field.getName();
    Field sourceField = null;
    
    try {
     sourceField = getField(sourceClass, name);
     
     field.setAccessible(true);
     sourceField.setAccessible(true);
     field.set(desteny, sourceField.get(source));
     
    } catch(IllegalAccessException e) {
     try {
      String methodName = capitalize(sourceField.getName());
      Method method;
      method = getMethod(sourceClass, "get" + methodName);
      method.setAccessible(true);
      field.set(desteny, method.invoke(source));
      
     } catch (IllegalArgumentException e1) {
      e1.printStackTrace();
     } catch (InvocationTargetException e1) {
      e1.printStackTrace();
     } catch (IllegalAccessException e1) {
      e1.printStackTrace();
     } catch (NoSuchMethodException e1) {
      e.printStackTrace();
     }
    } catch (NoSuchFieldException e) {
     e.printStackTrace();
    }
   }
  
  } catch (SecurityException e1) {
   throw new EWConversionException(e1.getMessage());
  } catch (InstantiationException e1) {
   throw new EWConversionException(e1.getMessage());
  } catch (IllegalAccessException e1) {
   throw new EWConversionException(e1.getMessage());
  }
  
  return desteny;
 }
 
 private static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
  Field field = null;
  while (clazz != Object.class) {
       try {
        field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        break;
       } catch (NoSuchFieldException ex) {
        clazz = clazz.getSuperclass();
       }
  }
  
  if (field == null)
   throw new NoSuchFieldException(field + " no such a field.");
  
  // only needed if the two classes are in different packages
  return field;
 }
 
 private static Method getMethod(Class<?> clazz, String methodName) throws NoSuchMethodException {
  Method method = null;
  while (clazz != Object.class) {
       try {
        method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true); 
        break;
       } catch (NoSuchMethodException ex) {
        clazz = clazz.getSuperclass();
       }
  }
  
  if (method == null)
   throw new NoSuchMethodException(methodName + " no such a method.");
  
  // only needed if the two classes are in different packages
  return method;
 }
 
 @SuppressWarnings("unchecked")
 public static <T> HashSet<T> convertToHashSet(Collection<? extends GenericEntity> source, Class<T> destinationClass) throws EWConversionException {
  HashSet<T> returnCollection = new HashSet<T>();
  
  for (GenericEntity s : source) {
   T element = (T) ReflectionUtil.convertClass(s, destinationClass.getClass());
   returnCollection.add(element);
  }
  
  return returnCollection;
 }

 
 @SuppressWarnings("unchecked")
 public static <T> Map<Long, T> convertToMap(Collection<? extends GenericEntity> source, Class<T> destinationClass) throws EWConversionException {
  Map<Long, T> returnCollection = new HashMap<Long, T>();
  
  for (GenericEntity s : source) {
   T element = (T) ReflectionUtil.convertClass(s, destinationClass.getClass());
   returnCollection.put(s.getId(), element);
  }
  
  return returnCollection;
 }
 
 public static <T> List<T> convertToArrayList(Collection<? extends GenericEntity> source, Class<T> destinationClass) throws EWConversionException {
  List<T> returnCollection = new ArrayList<T>();
  
  for (GenericEntity s : source) {
   T element = (T) ReflectionUtil.convertClass(s, destinationClass);
   returnCollection.add(element);
  }
  
  return returnCollection;
 }
 
}

I also provide a couple of methods to help on more complex conversions, such as Map, List and Sets. GenericEntity is an abstract class from where all entities inherit.

I made some performance test with a class that has 5 attributes, based on the supposed that both has the same attributes. As a mean I get 2 milliseconds for the traditional way of fill one class with the content of the other one, and on the other hand an 8 milliseconds mean using the utility class.

I think that this is very useful for non real time applications and avoid you from being specific converting code for each class you need to send back to the client layer.

This is a wide open discussion field and most of you should have different opinions. The aim is to present one way of doing this. If you have buts or other ways to do this please don't hesitate to post a comment.

If you want to get more in deep details on "Java Reflection API" you can read this tutorial. He gave very good explanations on this concern.

See you!!

Tuesday 6 July 2010

An overview of the defalut GWT application.

GWT is basically a translator(very big and complex one) that mainly translates the Java programming language to the JavaScript programming language. It sounds easy but it's not. This is a very innovative idea that allows us to work on web applications like in Swing. For those who have some experience in Swing programming so GWT looks like very familiar.

GWT not only translate from one language to another, also offers a lot of libraries to get easy the most common things on the web development.
Those are some of the features that GWT offers:
  • Dynamic and reusable UI components: programmers can use pre-designed classes to implement otherwise time-consuming dynamic behaviors, such as drag-and-drop or sophisticated visual tree structures.
  • Simple RPC mechanism
  • Browser history management
  • Support for full-featured Java debugging
  • GWT handles all cross-browser issues for the developer.
  • JUnit integration
  • Easy internationalization
those are some of the most remarkable features.

This intend to be an overview of a very basic GWT application. My intention is to explain briefly and with my very basic knowledge how does it works.

Here we're going to explain the process to get a running environment on Eclipse for linux. In order to do that, you can follow this recipe. Take into account that the last version of Eclipse is 3.6 Helios, so you can use the appropriate plug-in version.

As it says the recipe, to create a Web Application, select File > New > Web Application Project from the Eclipse menu.

In the New Web Application Project wizard, enter a name for your project and a java package name, on our example com.example.firstproject. If you installed the Google App Engine SDK, the wizard gives you the option to use App Engine as well. For now, uncheck this option and click Finish.

Now we have our first GWT project. The wizard generates all necessary to get us a running project. This is a great aid, and allows us to be on the road very fast.

That's how "project view" should looks like:


As we can see, there are four packages that were created following the pattern we gave to the wizard.

The first thing we going to look at, is the FirstProject.gwt.xml file. This file is to configure the GWT application module. In this file we will set the EntryPoint, which is the class that will be responsible of start the application. The method that will be called is onModuleLoad() and here you have to write your code.

As you can see in FirstProject.gwt.xml file, the default EntryPoint class was set:



That way, GWT knows from where to start when a client invocation arrives.

Now we going to pay attention to onModuleLoad() method. The significant thing to notice here is the connection between this and the main page. The "main page" is how I called to the basic html page where you set the layout. In this case this page is /war/FirstProject.html. The body of this page will be represented by the RootPanel class. That class allows you to get any object by his name. So the the trick here is to place some named properly(nameFieldContainer for example) and then get it using RootPanel.get("nameFieldContainer") to add widgets to it. As can be seen in the example, a TextBox is created and labeled "GWT User" for lastly being added to nameFieldContainer.

final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final Label errorLabel = new Label();

// We can add style names to widgets
sendButton.addStyleName("sendButton");

// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);


Similarly, sendButton and errorLabel, are added to their respective root panels.




Furthermore, we can observe the creation of an event handler class. This class will manage the events that it implements. In this case we are talking about ClickHandler and KeyUpHandler. As you can see, this class overrides two methods, onClick and onKeyUp. Then this handler is set to the button and to the TextBox.

We have also the implementation of communication between the client and the server. This is achieved using RPC(remote procedure calls), GWT has he's own implementation of that design pattern. The good news is that is very simple to use.

There are a couple of things to do here. First we have to add the servlet to web.xml. This file is located as usual, in /war/WEB-INF, and you will see that piece of code that means that:

  
    greetServlet
    com.example.firstproject.server.GreetingServiceImpl
  
  
  
    greetServlet
    /firstproject/greet
  


As we can see in the servlet mapping url, we are pointing the servlet to "/firstproject/greet". The following part of the project name is the relative path and is the one that must be used in the RPC interface. Now, if we take a look at GreetingService interface we will see the reference to "greet".

package com.example.firstproject.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
    String greetServer(String name) throws IllegalArgumentException;
}


In that interface we will define the methods to be called. In this case we can see greetServer method that is the only one we going to use.

Now we have the implementation of that interface that is the responsible to answer:

package com.example.firstproject.server;

import com.example.firstproject.client.GreetingService;
import com.example.firstproject.shared.FieldVerifier;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {

    public String greetServer(String input) throws IllegalArgumentException {
        // Verify that the input is valid. 
        if (!FieldVerifier.isValidName(input)) {
            // If the input is not valid, throw an IllegalArgumentException back to
            // the client.
            throw new IllegalArgumentException("Name must be at least 4 characters long");
        }

        String serverInfo = getServletContext().getServerInfo();
        String userAgent = getThreadLocalRequest().getHeader("User-Agent");

        // Escape data from the client to avoid cross-site script vulnerabilities.
        input = escapeHtml(input);
        userAgent = escapeHtml(userAgent);

        return "Hello, " + input + "!

I am running " + serverInfo + ".

It looks like you are using:
" + userAgent;
    }

    /**
     * Escape an html string. Escaping data received from the client helps to
     * prevent cross-site script vulnerabilities.
     * 
     * @param html the html string to escape
     * @return the escaped string
     */
    private String escapeHtml(String html) {
        if (html == null) {
            return null;
        }
        return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
    }
}


Now it's time to play. I did some little things that I will share on later posts.

I hope that will be useful!!