Visualizzazione post con etichetta bean. Mostra tutti i post
Visualizzazione post con etichetta bean. Mostra tutti i post

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!