domenica 13 gennaio 2013

Class generation with Javassist

With this post you will see how it's easy to create at runtime a class with javassist.
We will go to create a simple javaBean that extends an interface.
The interface is defined at development time as follows:
public interface IBean {

   public String getField();

   public void setField(String field);

}

Now we will create the Bean class at runtime that extends the IBean interface:
public class Generate {
   // If a program is running on a web application server such as JBoss and Tomcat,
   // the ClassPool object may not be able to find user classes.
   // In that case, an additional class path must be registered to the ClassPool.
   static{
      // ClassPool initialization
      ClassPool.getDefault().insertClassPath(new ClassClassPath(IBean.class));
   }

   public static IBean bean(){

      ClassPool cp = ClassPool.getDefault();

      // creation of the class
      CtClass Bean = cp.makeClass("Bean");
      
      // addition of the interface
      Bean.addInterface(cp.get(IBean.class.getName()));

      // creation of an empty constructor
      CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, Bean);

      // its body
      ctConstructor.setBody(";");

      // addition of the constructor
      Bean.addConstructor(ctConstructor);

      // addition of the String field
      Bean.addField(new CtField(cp.get(String.class.getName()), "field", Bean));

      // creation of getField method
      CtMethod getField = CtNewMethod.make("public String getField(){ return field; }",Bean);

      // add method to CtClass
      Bean.addMethod(getField); 

      // creation of setField method
      CtMethod setField = CtNewMethod.make("public void setField(String field){ this.field = field; }",Bean);

      // add method to CtClass
      Bean.addMethod(setField); 

      return (IBean) Bean.toClass().newInstance();

   }
}

In this mode we can create an instance of IBean dynamically, using the IBean interface at development time:
IBean bean = Generate.bean();
bean.setField("example");
assertEqual("example",bean.getField());

The exceptions aren't handled to increase the readability.
This technique is used in the development of JMapper Framework: http://code.google.com/p/jmapper-framework/ You can download the source.jar or checkout the code from svn.

giovedì 10 gennaio 2013

JMapper Framework 1.1.1 released!

With this released the features added are:

Inherited configuration

Now we can define a common configuration/conversions in the superclass, less code, less redundance and less maintenance.

Implicit conversion between arrays and collections

With this features we can configure arrays with collections and vice versa, with any type of items (primitive, wrapper and mapped).

OneToMany method changed

To prevent unexpected behavior in case of singleton pattern usage in multi-threaded environment, the definition of the target class will be done through the passage of the class as input to the method. For more information: http://code.google.com/p/jmapper-framework/

venerdì 4 gennaio 2013

how to generate the hql query from the instance

In some cases we have the need to transform an object in an hql query considering only the valued properties, going in introspection also. For example, we have the following class:
class Bean{

   Integer id;
   String description;
   String other;

   // getter and setter..
}
The scope is to include in the HQL query only the valorized properties of this bean. then we immediately think of a cascade of if:
String hql = "Select Bean from Bean";
boolean isWhere = true;

if(bean.getId() != null) {
   if(isWhere){
      hql += " Where ";
      isWhere = false; 
   }else{
      hql += " and ";
   }
   hql += "Bean.id = " + bean.getId();
}

if(bean.getDescription() != null) {
   if(isWhere){
      hql += " Where ";
      isWhere = false; 
   }else{
      hql += " and ";
   }
   hql += "Bean.id = " + bean.getDescription();
}

// etc..
The result is a HQL query generated at runtime, but the code written isn't generic and you must in all cases write custom code. Follows an algorithm created by me, a recursive function that permits to write hql query in every situation:
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;

class Generate {

   private boolean isWhere;
 
   public String hql(Object obj){
        isWhere = true;
        String alias = ob.getClass().getSimpleName().toLowerCase();
        return hql(obj, alias, true);
   }

   private String hql(Object ob, String alias, boolean isFirst){
     
      Class<? extends Object> obClass = ob.getClass();
      StringBuilder sb = new StringBuilder();
  
      if (isFirst)
         sb.append("SELECT "+alias+" FROM "+obClass.getSimpleName()+" as "+alias);

      try {

         for (Field field : obClass.getDeclaredFields()) {
              
            Class<?> fieldType = field.getType();
            String fieldName = field.getName();
    
            if(!isCollection(fieldType) && !isSerialVersionUID(fieldName)){
 
               Object fieldValue = null;
   
               try{ fieldValue = obClass.getMethod(mGet(fieldName)).invoke(ob);
               }catch(Exception e){
                  // some fields don't have get method
                  // for example serialVersionUID    
               }
     
               if (fieldValue != null)

                  // if the field is complex type it goes into introspection
                  if (isFk(fieldType))
                     sb.append(hql(fieldValue, alias+"."+fieldName, false));
                  
                  else { 
                     if (isWhere) { 
                        sb.append(" WHERE ");
                        isWhere = false;
                     } else 
                        sb.append(" AND ");
   
                     sb.append(alias+"."+fieldName+" = "+getValue(fieldValue, fieldType));
                  }
             }
          }
      } catch (Exception e) { /** to handle **/ }

      return sb.toString();
   }
    
   private String getValue(Object value, Class<?> field) {

        StringBuilder sb = new StringBuilder();
 
        try { if (field.equals(String.class)
               || field.equals(Character.class)
               || field.equals(char.class))    sb.append("'"+value+"'");

              else
                 if(field.equals(Date.class))  sb.append("to_timestamp('"+value+"')");
                 else                          sb.append(value);
     
        } catch (Exception e) { /** to handle **/ }

        return sb.toString();
   }
 

   public static final ArrayList basicTypes = 
   
   new ArrayList(){
      private static final long serialVersionUID = -5567529960231273742L;

      {
        add(byte.class.getName());
        add(short.class.getName());
        add(int.class.getName());
        add(long.class.getName());
        add(float.class.getName());
        add(double.class.getName());
        add(char.class.getName());
        add(boolean.class.getName());
        add(Byte.class.getName());
        add(Short.class.getName());
        add(Integer.class.getName());
        add(Long.class.getName());
        add(Float.class.getName());
        add(Double.class.getName());
        add(Character.class.getName());
        add(Boolean.class.getName());
        add(String.class.getName());
        add(Date.class.getName());
      }
   };
 
   private boolean isCollection(Class<?> aClass){
      return Collection.class.isAssignableFrom(aClass);
   }
 
   private String mGet(String s) {
      return "get" + s.substring(0, 1).toUpperCase() + s.substring(1);
   }
 
   private boolean isSerialVersionUID(String field) {
      return field.equals("serialVersionUID");
   }

   private boolean isFk(Class<?> field) {
      return !basicTypes.contains(field.getName());
   }
} 
The exceptions aren't handled so to focalize the attention on the algorithm. An example of use:
   Bean bean = new Bean(2013,"description");
   
   String hql = new Generate().hql(bean);

   assertEqual("SELECT bean FROM Bean as bean WHERE bean.id = 2013 and bean.description = 'description'", hql);

mercoledì 2 gennaio 2013

JMapper Framework

Hello to All,

with this my first post i wanted to bring to your attention a new java bean mapping framework "JMapper" that allows 
you to perform dynamic mappings with annotations and / or XML bringing 
several advantages as: 
- create and enrich target objects 
- apply specific logic to the mapping (only valued fields, null fields 
only, etc. ..) 
- automated management of the XML file 
- Possibility of Implementing the 1 to N and N to 1 relationships 
- explicit conversions 

JMapper permits to have all advantages of dynamic mapping with the 
performance of static code. 

http://code.google.com/p/jmapper-framework/

thank you for your attention!