org.soybeanMilk.core.bean.PropertyInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.soybeanMilk.core.bean.PropertyInfo.java

Source

/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package org.soybeanMilk.core.bean;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.soybeanMilk.SbmUtils;

/**
 * {@linkplain java.lang.Class Class}??
 * @author earthangry@gmail.com
 * @date 2010-4-4
 */
public class PropertyInfo {
    private static Log log = LogFactory.getLog(PropertyInfo.class);

    /**?*/
    private Class<?> ownerClass;

    /***/
    private Class<?> propType;
    /***/
    private Type propGenericType;

    /**???*/
    private Map<String, PropertyInfo> subPropertyInfos;

    /***/
    private Method readMethod;

    /***/
    private Method writeMethod;

    /**??*/
    private String propName;

    protected PropertyInfo(Class<?> propertyType) {
        this(null, propertyType, null, null, null);
    }

    protected PropertyInfo(Class<?> ownerClass, Class<?> propType, String propName, Method readMethod,
            Method writeMethod) {
        super();
        this.ownerClass = ownerClass;
        this.propType = propType;
        this.propName = propName;
        this.readMethod = readMethod;
        this.writeMethod = writeMethod;

        if (writeMethod != null)
            this.propGenericType = writeMethod.getGenericParameterTypes()[0];
        else
            this.propGenericType = propType;
    }

    /**
     * ??
     * @return
     * @date 2011-10-9
     */
    public Class<?> getOwnerClass() {
        return ownerClass;
    }

    public void setOwnerClass(Class<?> ownerClass) {
        this.ownerClass = ownerClass;
    }

    /**
     * ?{@linkplain Class}
     * @return
     * @date 2010-12-28
     */
    public Class<?> getPropType() {
        return propType;
    }

    protected void setPropType(Class<?> propType) {
        this.propType = propType;
    }

    /**
     * ?????
     * @return
     * @date 2010-12-28
     */
    public Type getPropGenericType() {
        return propGenericType;
    }

    protected void setPropGenericType(Type propGenericType) {
        this.propGenericType = propGenericType;
    }

    /**
     * ?????<code>null</code><code>int</code>
     * @return
     * @date 2010-12-28
     */
    public Map<String, PropertyInfo> getSubPropertyInfos() {
        return subPropertyInfos;
    }

    protected void setSubPropertyInfos(Map<String, PropertyInfo> subPropertyInfos) {
        this.subPropertyInfos = subPropertyInfos;
    }

    /**
     * ?
     * @return
     * @date 2010-12-28
     */
    public Method getReadMethod() {
        return readMethod;
    }

    protected void setReadMethod(Method readMethod) {
        this.readMethod = readMethod;
    }

    /**
     * ?
     * @return
     * @date 2010-12-28
     */
    public Method getWriteMethod() {
        return writeMethod;
    }

    protected void setWriteMethod(Method writeMethod) {
        this.writeMethod = writeMethod;
    }

    /**
     * ???
     * @return
     * @date 2012-2-26
     */
    public String getPropName() {
        return propName;
    }

    protected void setPropName(String propName) {
        this.propName = propName;
    }

    /**
     * ??
     * @param propertyInfo
     * @date 2010-12-28
     */
    public void addSubPropertyInfo(PropertyInfo propertyInfo) {
        if (subPropertyInfos == null)
            subPropertyInfos = new HashMap<String, PropertyInfo>();

        if (propertyInfo.getPropName() == null)
            throw new IllegalArgumentException("the name of this PropertyInfo must not be null.");

        subPropertyInfos.put(propertyInfo.getPropName(), propertyInfo);
    }

    /**
     * ???
     * @param name ??
     * @return
     */
    public PropertyInfo getSubPropertyInfo(String name) {
        return subPropertyInfos == null ? null : subPropertyInfos.get(name);
    }

    /**
     * ???
     * @return
     * @date 2011-1-2
     */
    public boolean hasSubPropertyInfo() {
        return this.subPropertyInfos != null && !this.subPropertyInfos.isEmpty();
    }

    //@Override
    public String toString() {
        return getClass().getSimpleName() + " [name=" + propName + ", type=" + propType + ", genericType="
                + propGenericType + "]";
    }

    /**
     * 
     */
    private static ConcurrentHashMap<Class<?>, PropertyInfo> propertyInfoCache = new ConcurrentHashMap<Class<?>, PropertyInfo>();

    /**
     * ???<code>propertyType</code>?<code>beanClass</code><code>PropertyInfo</code>
     * @param beanClass
     * @return
     * @date 2010-12-28
     */
    public static PropertyInfo getPropertyInfo(Class<?> beanClass) {
        if (beanClass == null)
            return null;

        PropertyInfo beanInfo = null;

        beanInfo = propertyInfoCache.get(beanClass);
        if (beanInfo == null) {
            Map<Class<?>, PropertyInfo> localExists = new HashMap<Class<?>, PropertyInfo>();
            beanInfo = getPropertyInfoAnatomized(beanClass, localExists, 0);
        } else {
            if (log.isDebugEnabled())
                log.debug("get " + SbmUtils.toString(beanClass) + " property information from cache");
        }

        return beanInfo;
    }

    private static PropertyInfo getPropertyInfoAnatomized(Class<?> beanClass,
            Map<Class<?>, PropertyInfo> localExists, int depth) {
        PropertyInfo cached = propertyInfoCache.get(beanClass);
        if (cached != null) {
            if (log.isDebugEnabled())
                log.debug(getSpace(depth) + "got " + SbmUtils.toString(beanClass)
                        + " property information from cache");

            return cached;
        }

        if (log.isDebugEnabled())
            log.debug(getSpace(depth) + "start  anatomizing " + SbmUtils.toString(beanClass)
                    + " property information");

        PropertyInfo beanInfo = new PropertyInfo(beanClass);

        localExists.put(beanInfo.getPropType(), beanInfo);

        PropertyDescriptor[] pds = null;

        try {
            pds = Introspector.getBeanInfo(beanInfo.getPropType()).getPropertyDescriptors();
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        }

        if (pds == null || pds.length == 0)
            ;
        else {
            for (PropertyDescriptor pd : pds) {
                String name = pd.getName();
                Method wm = pd.getWriteMethod();
                Method rm = pd.getReadMethod();
                Class<?> propertyClazz = pd.getPropertyType();

                //?
                if (wm == null || rm == null || !Modifier.isPublic(wm.getModifiers())
                        || !Modifier.isPublic(rm.getModifiers()))
                    continue;

                //localExists?PropertyInfo
                PropertyInfo exist = localExists.get(propertyClazz);
                if (exist == null)
                    exist = getPropertyInfoAnatomized(propertyClazz, localExists, depth + 1);

                //???
                PropertyInfo copied = new PropertyInfo(beanClass, propertyClazz, name, rm, wm);
                copied.setSubPropertyInfos(exist.getSubPropertyInfos());

                beanInfo.addSubPropertyInfo(copied);

                if (log.isDebugEnabled())
                    log.debug(getSpace(depth) + " add " + SbmUtils.toString(copied));
            }
        }

        if (log.isDebugEnabled())
            log.debug(getSpace(depth) + "finish anatomizing " + SbmUtils.toString(beanClass)
                    + " property information");

        propertyInfoCache.putIfAbsent(beanClass, beanInfo);

        return beanInfo;
    }

    private static String getSpace(int len) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++)
            sb.append("    ");

        return sb.toString();
    }
}