All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.x5.util.ObjectDataMap Maven / Gradle / Ivy

There is a newer version: 3.6.2
Show newest version
package com.x5.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ObjectDataMap
 * 
 * Box POJO/Bean inside a Map.  When accessed, pry into POJO/Bean using
 * reflection/introspection and pull out all public member fields/properties.
 * Convert field names from camelCase to lower_case_with_underscores
 * Convert bean properties from getSomeProperty() to some_property
 *  or isVeryHappy() to is_very_happy
 * 
 * Values returned are copies, frozen at time of first access.
 * 
 */
@SuppressWarnings("rawtypes")
public class ObjectDataMap implements Map
{
    private Map pickle = null;
    private Object object;
    private boolean isBean = false;
    
    private static final Map EMPTY_MAP = new HashMap();
    
    private static final HashSet> WRAPPER_TYPES = getWrapperTypes();

    private static HashSet> getWrapperTypes()
    {
        HashSet> ret = new HashSet>();
        ret.add(Boolean.class);
        ret.add(Character.class);
        ret.add(Byte.class);
        ret.add(Short.class);
        ret.add(Integer.class);
        ret.add(Long.class);
        ret.add(Float.class);
        ret.add(Double.class);
        ret.add(Void.class);
        return ret;
    }
    
    public static boolean isWrapperType(Class clazz)
    {
        return WRAPPER_TYPES.contains(clazz);
    }

    public ObjectDataMap(Object pojo)
    {
        this.object = pojo;
    }
    
    private void init()
    {
        if (pickle == null) {
            pickle = mapify(object);
            // prevent multiple expensive calls to mapify
            // when result is null
            if (pickle == null) {
                pickle = EMPTY_MAP;
            }
        }
    }
    
    public static ObjectDataMap wrapBean(Object bean)
    {
        if (bean == null) return null;
        ObjectDataMap boxedBean = new ObjectDataMap(bean);
        boxedBean.isBean = true;
        
        return boxedBean;
    }
    
    private Map mapify(Object pojo)
    {
        if (isBean) {
            try {
                return mapifyBean(pojo);
            } catch (java.beans.IntrospectionException e) {
                // hmm, not a bean after all...
            }
        }
        
        Field[] fields = pojo.getClass().getDeclaredFields();
        Map pickle = null;
        
        for (int i=0; i();
                // convert isActive to is_active
                paramName = splitCamelCase(paramName);
                storeValue(pickle, paramClass, paramName, paramValue);
            }
        }
        
        return pickle;
    }
    
    private Map mapifyBean(Object bean)
    throws java.beans.IntrospectionException
    {
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
        PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
        
        if (properties == null) return null;
        
        Map pickle = null;
        
        // copy properties into hashtable
        for (PropertyDescriptor property : properties) {
            Class paramClass = property.getPropertyType();
            Method getter = property.getReadMethod();
            try {
                Object paramValue = getter.invoke(bean, (Object[])null);

                if (paramValue != null) {
                    // converts isActive() to is_active
                    // converts getBookTitle() to book_title
                    String paramName = property.getName();
                    paramName = splitCamelCase(paramName);
                    if (paramValue instanceof Boolean) {
                        paramName = "is_"+paramName;
                    }
                    
                    if (pickle == null) pickle = new HashMap();
                    
                    storeValue(pickle, paramClass, paramName, paramValue);
                }
            } catch (InvocationTargetException e) {
            } catch (IllegalAccessException e) {
            }
        }
        
        return pickle;
    }

    private void storeValue(Map pickle, Class paramClass,
                            String paramName, Object paramValue)
    {
        if (paramClass.isArray() || paramValue instanceof List) {
            pickle.put(paramName, paramValue);
        } else if (paramClass == String.class) {
            pickle.put(paramName, paramValue);
        } else if (paramValue instanceof Boolean) {
            if (((Boolean)paramValue).booleanValue()) {
                pickle.put(paramName, "TRUE");
            }
        } else if (paramClass.isPrimitive() || isWrapperType(paramClass)) {
            pickle.put(paramName, paramValue.toString());
        } else if (paramValue == this) {
            // tiny optimization
            pickle.put(paramName, this);
        } else {
            // box all non-primitive object member fields
            // in their own ObjectDataMap wrapper.
            // lazy init guarantees no infinite recursion here.
            ObjectDataMap boxedParam = isBean ? wrapBean(paramValue) : new ObjectDataMap(paramValue);
            pickle.put(paramName, boxedParam);
        }
        
    }
    
    // splitCamelCase converts SimpleXMLStuff to Simple_XML_Stuff
    public static String splitCamelCase(String s)
    {
       return s.replaceAll(
          String.format("%s|%s|%s",
             "(?<=[A-Z])(?=[A-Z][a-z])",
             "(?<=[^A-Z])(?=[A-Z])",
             "(?<=[A-Za-z])(?=[^A-Za-z])"
          ),
          "_"
       ).toLowerCase();
    }
    
    public int size()
    {
        init();
        return pickle.size();
    }

    public boolean isEmpty()
    {
        init();
        return pickle.isEmpty();
    }

    public boolean containsKey(Object key)
    {
        init();
        return pickle.containsKey(key);
    }

    public boolean containsValue(Object value)
    {
        init();
        return pickle.containsValue(value);
    }

    public Object get(Object key)
    {
        init();
        return pickle.get(key);
    }

    public Object put(Object key, Object value)
    {
        // unsupported
        return null;
    }

    public Object remove(Object key)
    {
        // unsupported
        return null;
    }

    public void putAll(Map m)
    {
        // unsupported
    }

    public void clear()
    {
        // unsupported
    }

    public Set keySet()
    {
        init();
        return pickle.keySet();
    }

    public Collection values()
    {
        init();
        return pickle.values();
    }

    public Set entrySet()
    {
        init();
        return pickle.entrySet();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy