I use a custom very lightweight persistence library that does lazy loading using CGLIB Enhanced proxy.
THe generated proxy for domain objects use Key/value Map data fed to it via a static factory method.
When a get or set method is called for the wrapped domain, the proxy check the value for the field in the Map,
if it finds an entry for the field, which means the field hasn’t been initialised, it sets the field value from Map and removes
the entry from the Map.
If no entry is found in the Map, the method returns value of the field of the domain object encapsulated by the getter method
rather than getting it from the Map.

Of course if the field is a domain object, then the object is fetched using the PK value in the Map.
That gives me the same lazy loading voodoo magic like Hibernate- the 10 pound gorrila.
The persistence is backed by a cache which looks at a domain’s metadata and
only caches those that are specified as cacheable.

Everything works like a charm except that the CGLIB enhanced objects don’t play nice with XStream at all.
When serializing enhanced objects XStream spits out gory details of classe/superclasses/interfaces and full dissection of a Map that is fed to a static method when creating the proxy object, when all i want is the pojo object wrapped by the proxy.

I believe the XStream library simply gets the value of the field rather than calling the getter method using reflection when serializing.
That must be the reason that in my case all serialised objects have empty values for fields because the fields don’t get set when the proxy is
created, they get set only setter method is called on it or getter method is called for the first time .
I think that’s the same problem with Hibernate and I guess that’s the reason it throws Lazy Initilization Exception.

I tried the CGLIBEnhancedConverter that comes with the library but it didn’t work for me.
I couldn’t find a simple enough solution in the internet and the ones I found were all Hibernate specific.
Since this is the second time I had been trying to solve the issue, I decided to push forward and find a work around myself.

After trying out a few different solutions I finally came up with a dead simple solution.
IT involves a static method to deproxy the enhanced domain objects and a XStream custom converter class.
There may be performance cost as it uses reflection eventhough getter setter methods for domain classes are cached for reuse.

Here’s the simplified method.


  /**
     * Deproxies a CGLIB enhanced proxy object
     * @param <T>
     * @param proxy
     * @return deproxied domain object
     */
    public static <T > T deproxyReflection(final T proxy) {

      Class entityClass = proxy.getClass().getSuperclass();

        T entity = (T) ClassUtil.getInstance(entityClass);

        Field[] fields =  entityClass.getDeclaredFields();

        for (Field f : fields) {
            try {

	 // no need to set the values of collections as they won;t be serialized.
                //we just need the actaul properties taht amp to table columns
                if(List.class.isAssignableFrom(f.getType()))
                    continue;

                //I use a utility method to fetch getter/setter methods.
                //it simply loops through the object and super class to find the methods.
//so instead of screwing arund with the field's security settings we'll use getters/setters to ensure its unintrusive
                Method getter = ClassUtil.getPojoMethod(entityClass, f.getName(), ClassUtil.MethodType.GETTER);
                Method setter = ClassUtil.getPojoMethod(entityClass, f.getName(), new Class[]{f.getType()}, ClassUtil.MethodType.SETTER);

                Object val = getter.invoke(proxy, null);
                setter.invoke(entity, new Object[]{val});

            } catch (Exception ex) {
                Logger.getLogger(EntityProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                f.set(entity, f.get(proxy));
            } catch (Exception ex) {
                Logger.getLogger(EntityProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
            } 

        }

        return entity;
    }

We need to register a converter with XStream that used the above method to sanitize the domain objects before serializing.


/**
 * XStream converter to convert a CGLIB enhanced proxy  to the wrapped pojo object.
 *
 */
public class CGLIBEnhancedEntityConverter implements Converter {

    public boolean canConvert(Class clazz) {
        return (Enhancer.isEnhanced(clazz)  || clazz == CGLIBMapper.Marker.class) ;
    }

    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {

            // deproxy before sending it off the chain for serialization. ANd that's it.
           // XStream will get a simple pojo object and it will serialize it like any other pojo object.
         context.convertAnother(EntityProxyFactory.deproxyReflection(source));

    }

    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

    throw new Error("not supported");
    }

}

And that’s it. That’s all it takes.
If a domain object has other domain objects as fields, those fields will not be handled by the above method.
For that there are two choices. Firstly you can look at the field’s class type and say if t implements or extends your base Domain class/interface, you can deproxy them recursively.
In my case all domain objects implement a bare minimum interface called IEntity with only one getId() method.

the above method can be modified to recursively deproxy/sanitize a domain’s fields if they are proxied objects.


//.............
            Object val = getter.invoke(proxy, null);

                if (IEntity.class.isAssignableFrom(f.getType()) {
                    val=deproxy(val);//recursively deproxy the fields if they are enhanced objects
                }
                setter.invoke(entity, new Object[]{val});

If you only have to serialize a handful of domain objects, it might be better to register converters
for those fields at startup instead of using the above method.

Say, we have a domain class State with Country as one of its field, we can register the above converter to convert the country object as below.


//.............
//entity manager that handles all persistence needs
IEntityManager em= (IEntityManager) BeanFactory.getBean("entityManager");

//fetch a list of State objects with id smaller than3
       List<State> list= em.fetch(State.class, "id<3");

//uses factory method to instantiate Xstream
xstream xstream= XStreamFactory.getXstream(Format.JSON);

CGLIBEnhancedEntityConverter cglibConverter= new CGLIBEnhancedEntityConverter();

//register default converter
xstream.registerConverter(cglibConverter);

//register field converter. country field for State objects
xstream.registerLocalConverter(State.class, "country", cglibConverter);

//spit out the serialized json objects
 System.out.println(xs.toXML(list));

here’s the result without deproxying the domain object:
The before version :-)


{"list": [
  {
    "code": "",
    "name": "",
    "daylightSavingStart": "",
    "daylightSavingEnd": "",
    "CGLIB$BOUND": true,
    "CGLIB$CALLBACK_0": {
      "@class": "com.barahisolutions.proxy.EntityProxyFactory$EntityMethodInterceptor",
      "data": [
        {},
        {
          "default": {
            "loadFactor": 0.75,
            "threshold": 12
          },
          "int": 16,
          "int": 8,
          "string": "id",
//..................................................
//there's 10 times more of this garbage which i didn;t bother to print out.

And here's the nice and clean pojo version of the deproxied proxy objects.
I used the recursive option to inspect properties if objects and deproxy them if they are proxied domain
objects.
The after version :-)


{"list": [
  {
    "id": 1,
    "code": "NSW",
    "name": "New South Wales",
    "utcOffset": 10.0,
    "daylightSavingOn": false,
    "daylightSavingStart": "",
    "daylightSavingEnd": "",
    "country": {
      "id": 18,
      "code": "",
      "name": "Barbados"
    }
  },
  {
    "id": 2,
    "code": "VIC",
    "name": "Victoria",
    "daylightSavingOn": false,
    "daylightSavingStart": "",
    "daylightSavingEnd": "",
    "country": {
      "id": 12,
      "code": "AUS",
      "name": "Australia"
    }
  }
]}

I recently had to build a HTML select list with items grouped by category .
The list had to be populated using ajax as using simple jsp tag wasn’t enough as I needed other
properties besides simple key/ value and group for validation and displaying description of the selected item using javascript .

Since grouping objects can be quite quite handy for displaying grouped data in forms and in reports I ended up creating a utility method in java which takes a List of objects and a field name to group the objects by ,
and returns a map with keys as the values of the field name and values a a list of objects under this group.

Here’s the method .


    /**
     * Groups objects using field name provided
     *  @param list the list of objects to group
     * @param field the field to group the objects by
     * @return new Map containing list of objects.
     * The Map's key is the property specified in criteria object
     */

public static <V> Map<String,List<V>> group(List<V> list, String field) {

            //used for indexing to avoid too much looping
	     HashMap<String,K> index= new HashMap<String,K>();
      // the container for grouped data. K is the data type for the field's value.
        HashMap<K,List<V>> groupedData= new HashMap<K, List<V>>();

      // the method to invoke to get the value of the 'field' prop from objects
         Method m=null;

        try {
          V obj=list.get(0);
       // Used a handy Util Class's method for getting the getter method for 'field'
          m = ClassUtil.getMethod(obj.getClass(), "get"+StringUtil.getFirstUpper(field));
        } catch (NoSuchMethodException ex) {
            Logger.getLogger(ListUtil.class.getName()).log(Level.SEVERE, null, ex);

            return null;
        }

       //iterate through the list of objects passed as parameter
        for (V object : list) {

	//the 'field' value of object
             K columnVal=null;

             try {
                    columnVal = (K) m.invoke(object, null);

                     // group of objects under columnVal group
                       List<V> group=groupedData.get(index.get(columnVal.toString()));

                if(group==null){
                    group= new ArrayList<V>();
                groupedData.put(columnVal, group);
                index.put(columnVal.toString(), columnVal);
                }
                //add the object to the group
                group.add(object);

                } catch (Exception ex) {
                    Logger.getLogger(ListUtil.class.getName()).log(Level.SEVERE, null, ex);
                }
        }

        return groupedData;

}

here’s a simple test:


   List<Command> commands= new ArrayList();

//create objects to populate a list;

        Command comm= new DeviceCommand();
        comm.setCommand("CONTROL comm1");
        comm.setCommandType(CommandType.CONTROL);
        comm.setName(" CONTROL command 1");
        commands.add(comm);

          Command comm2= new DeviceCommand();
        comm2.setCommand("comm2");
        comm2.setCommandType(CommandType.CONTROL);
        comm2.setName(" CONTROL command 2");
        commands.add(comm2);

          Command comm3= new DeviceCommand();
        comm3.setCommand("INFORMATION comm1");
        comm3.setCommandType(CommandType.INFORMATION);
        comm3.setName("INFORMATION command 1");
        commands.add(comm3);

          Command comm5= new DeviceCommand();
        comm5.setCommand("SETTING comm1");
        comm5.setCommandType(CommandType.SETTING);
        comm5.setName("SETTING command 1");
        commands.add(comm5);

          Command comm6= new DeviceCommand();
        comm6.setCommand("SETTING comm2");
        comm6.setCommandType(CommandType.SETTING);
        comm6.setName("SETTING command 2");
        commands.add(comm6);

           Command comm8= new DeviceCommand();
        comm8.setCommand("OTHER comm1");
        comm8.setCommandType(CommandType.OTHER);
        comm8.setName("OTHER command 1");
        commands.add(comm8);

          Command comm4= new DeviceCommand();
        comm4.setCommand("CONTROL comm4");
        comm4.setCommandType(CommandType.CONTROL);
        comm4.setName("CONTROL  command 4");
        commands.add(comm4);

           Command comm7= new DeviceCommand();
        comm7.setCommand("SETTING comm3");
        comm7.setCommandType(CommandType.SETTING);
        comm7.setName("SETTING command 3");
        commands.add(comm7);

          Command comm9= new DeviceCommand();
        comm9.setCommand("OTHER comm2");
        comm9.setCommandType(CommandType.OTHER);
        comm9.setName("OTHER command 2");
        commands.add(comm9);

          Command comm10= new DeviceCommand();
        comm10.setCommand("OTHER comm3");
        comm10.setCommandType(CommandType.OTHER);
        comm10.setName("OTHER command 3");
        commands.add(comm10);

      //convert  list of Command objects into a map with commandTpe as key and list of Commands within
    // that group as  map value.
        Map<String,List<Command>> grouped=ListUtil.group(commands, "commandType");

	//print out the grouped map data.
        System.out.println(grouped.toString());

And the string representation of the grouped data :

{OTHER=[OTHER command 1, OTHER command 2, OTHER command 3], SETTING=[SETTING command 1, SETTING command 2, SETTING command 3], CONTROL=[ CONTROL command 1,  CONTROL command 2, CONTROL  command 4], INFORMATION=[INFORMATION command 1]}