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

com.espertech.esper.event.bean.PropertyHelper Maven / Gradle / Ivy

There is a newer version: 7.1.0
Show newest version
/**************************************************************************************
 * Copyright (C) 2006-2015 EsperTech Inc. All rights reserved.                        *
 * http://www.espertech.com/esper                                                          *
 * http://www.espertech.com                                                           *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the GPL license       *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package com.espertech.esper.event.bean;

import com.espertech.esper.client.EventPropertyGetter;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.event.EventPropertyType;
import com.espertech.esper.event.WriteablePropertyDescriptor;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.*;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.*;

/**
 * This class offers utililty methods around introspection and CGLIB interaction.
 */
public class PropertyHelper
{
    /**
     * Return getter for the given method and CGLIB FastClass.
     * @param method to return getter for
     * @param fastClass is the CGLIB fast classs to make FastMethod for
     * @param eventAdapterService factory for event beans and event types
     * @return property getter
     */
    public static EventPropertyGetter getGetter(Method method, FastClass fastClass, EventAdapterService eventAdapterService)
    {
        // Get CGLib fast method handle
        FastMethod fastMethod = null;
        try
        {
            if (fastClass != null)
            {
                fastMethod = fastClass.getMethod(method);
            }
        }
        catch (Throwable ex)
        {
            log.warn(".getAccessors Unable to obtain CGLib fast method implementation, msg=" + ex.getMessage());
        }

        // Construct the appropriate property getter CGLib or reflect
        EventPropertyGetter getter;
        if (fastMethod != null)
        {
            getter = new CGLibPropertyGetter(method, fastMethod, eventAdapterService);
        }
        else
        {
            getter = new ReflectionPropMethodGetter(method, eventAdapterService);
        }

        return getter;
    }

    /**
     * Introspects the given class and returns event property descriptors for each property found
     * in the class itself, it's superclasses and all interfaces this class and the superclasses implements.
     * @param clazz is the Class to introspect
     * @return list of properties
     */
    public static List getProperties(Class clazz)
    {
        // Determine all interfaces implemented and the interface's parent interfaces if any
        Set propertyOrigClasses = new HashSet();
        getImplementedInterfaceParents(clazz, propertyOrigClasses);

        // Add class itself
        propertyOrigClasses.add(clazz);

        // Get the set of property names for all classes
        return getPropertiesForClasses(propertyOrigClasses);
    }

    /**
     * Introspects the given class and returns event property descriptors for each writable property found
     * in the class itself, it's superclasses and all interfaces this class and the superclasses implements.
     * @param clazz is the Class to introspect
     * @return list of properties
     */
    public static Set getWritableProperties(Class clazz)
    {
        // Determine all interfaces implemented and the interface's parent interfaces if any
        Set propertyOrigClasses = new HashSet();
        getImplementedInterfaceParents(clazz, propertyOrigClasses);

        // Add class itself
        propertyOrigClasses.add(clazz);

        // Get the set of property names for all classes
        return getWritablePropertiesForClasses(propertyOrigClasses);
    }

    private static void getImplementedInterfaceParents(Class clazz, Set classesResult)
    {
        Class[] interfaces = clazz.getInterfaces();

        if (interfaces == null)
        {
            return;
        }

        for (int i = 0; i < interfaces.length; i++)
        {
            classesResult.add(interfaces[i]);
            getImplementedInterfaceParents(interfaces[i], classesResult);
        }
    }

    private static Set getWritablePropertiesForClasses(Set propertyClasses)
    {
    	Set result = new HashSet();

        for (Class clazz : propertyClasses)
        {
        	addIntrospectPropertiesWritable(clazz, result);
        }

        return result;
    }

    private static List getPropertiesForClasses(Set propertyClasses)
    {
    	List result = new LinkedList();

        for (Class clazz : propertyClasses)
        {
        	addIntrospectProperties(clazz, result);
            addMappedProperties(clazz, result);
        }

        removeDuplicateProperties(result);
        removeJavaProperties(result);

        return result;
    }

    /**
     * Remove Java language specific properties from the given list of property descriptors.
     * @param properties is the list of property descriptors
     */
    protected static void removeJavaProperties(List properties)
    {
        List toRemove = new LinkedList();

        // add removed entries to separate list
        for (InternalEventPropDescriptor desc : properties)
        {
            if ((desc.getPropertyName().equals("class")) ||
                (desc.getPropertyName().equals("getClass")) ||
                (desc.getPropertyName().equals("toString")) ||
                (desc.getPropertyName().equals("hashCode")))
            {
                toRemove.add(desc);
            }
        }

        // remove
        for (InternalEventPropDescriptor desc : toRemove)
        {
            properties.remove(desc);
        }
    }

    /**
     * Removed duplicate properties using the property name to find unique properties.
     * @param properties is a list of property descriptors
     */
    protected static void removeDuplicateProperties(List properties)
    {
        LinkedHashMap set = new LinkedHashMap();
        List toRemove = new LinkedList();

        // add duplicates to separate list
        for (InternalEventPropDescriptor desc : properties)
        {
            if (set.containsKey(desc.getPropertyName()))
            {
                toRemove.add(desc);
                continue;
            }
            set.put(desc.getPropertyName(), desc);
        }

        // remove duplicates
        for (InternalEventPropDescriptor desc : toRemove)
        {
            properties.remove(desc);
        }
    }

    /**
     * Adds to the given list of property descriptors the properties of the given class
     * using the Introspector to introspect properties. This also finds array and indexed properties.
     * @param clazz to introspect
     * @param result is the list to add to
     */
    protected static void addIntrospectProperties(Class clazz, List result)
    {
        PropertyDescriptor properties[] = introspect(clazz);
        for (int i = 0; i < properties.length; i++)
        {
            PropertyDescriptor property = properties[i];
        	String propertyName = property.getName();
        	Method readMethod = property.getReadMethod();

        	EventPropertyType type = EventPropertyType.SIMPLE;
        	if (property instanceof IndexedPropertyDescriptor)
        	{
                readMethod = ((IndexedPropertyDescriptor) property).getIndexedReadMethod();
        		type = EventPropertyType.INDEXED;
        	}

            if (readMethod == null)
            {
                continue;
            }

            result.add(new InternalEventPropDescriptor(propertyName, readMethod, type));
        }
    }
   
    private static void addIntrospectPropertiesWritable(Class clazz, Set result)
    {
        PropertyDescriptor properties[] = introspect(clazz);
        for (int i = 0; i < properties.length; i++)
        {
            PropertyDescriptor property = properties[i];
        	String propertyName = property.getName();
        	Method writeMethod = property.getWriteMethod();

            if (writeMethod == null)
            {
                continue;
            }

            result.add(new WriteablePropertyDescriptor(propertyName, writeMethod.getParameterTypes()[0], writeMethod));
        }
    }

    /**
     * Adds to the given list of property descriptors the mapped properties, ie.
     * properties that have a getter method taking a single String value as a parameter.
     * @param clazz to introspect
     * @param result is the list to add to
     */
    protected static void addMappedProperties(Class clazz, List result)
    {
        Set uniquePropertyNames = new HashSet();
    	Method[] methods = clazz.getMethods();

    	for (int i = 0; i < methods.length; i++)
    	{
    		String methodName = methods[i].getName();
    		if (!methodName.startsWith("get"))
    		{
    			continue;
    		}

    		String inferredName = methodName.substring(3, methodName.length());
    		if (inferredName.length() == 0)
    		{
    			continue;
    		}

    		Class parameterTypes[] = methods[i].getParameterTypes();
    		if (parameterTypes.length != 1)
    		{
    			continue;
    		}

    		if (parameterTypes[0] != String.class)
    		{
    			continue;
    		}

    		String newInferredName = null;
            // Leave uppercase inferred names such as URL
    		if (inferredName.length() >= 2)
            {
                if ((Character.isUpperCase(inferredName.charAt(0))) &&
    			    (Character.isUpperCase(inferredName.charAt(1))))
                {
                    newInferredName = inferredName;
                }
            }
    		// camelCase the inferred name
            if (newInferredName == null)
    		{
    			newInferredName = Character.toString(Character.toLowerCase(inferredName.charAt(0)));
    			if (inferredName.length() > 1)
    			{
    				newInferredName += inferredName.substring(1, inferredName.length());
    			}
    		}
    		inferredName = newInferredName;

            // if the property inferred name already exists, don't supply it
            if (uniquePropertyNames.contains(inferredName))
            {
                continue;
            }

    		result.add(new InternalEventPropDescriptor(inferredName, methods[i], EventPropertyType.MAPPED));
            uniquePropertyNames.add(inferredName);
    	}
    }

    /**
     * Using the Java Introspector class the method returns the property descriptors obtained through introspection.
     * @param clazz to introspect
     * @return array of property descriptors
     */
    protected static PropertyDescriptor[] introspect(Class clazz)
    {
        BeanInfo beanInfo;

        try
        {
            beanInfo = Introspector.getBeanInfo(clazz);
        }
        catch (IntrospectionException e)
        {
            return (new PropertyDescriptor[0]);
        }

        return beanInfo.getPropertyDescriptors();
    }

    public static String getGetterMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "get");
    }

    public static String getSetterMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "set");
    }

    public static String getIsMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "is");
    }

    private static String getGetterSetterMethodName(String propertyName, String operation)
    {
        StringWriter writer = new StringWriter();
        writer.write(operation);
        writer.write(Character.toUpperCase(propertyName.charAt(0)));
        writer.write(propertyName.substring(1));
        return writer.toString();
    }

    private static final Log log = LogFactory.getLog(PropertyHelper.class);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy