Java tutorial
/** * 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(); } }