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

lite.beans.Introspector Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 lite.beans;

import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * The Introspector is a utility for developers to figure out
 * which properties, events, and methods a JavaBean supports.
 * 

* The Introspector class walks over the class/superclass chain * of the target bean class. At each level it checks if there is a matching * BeanInfo class which provides explicit information about the * bean, and if so uses that explicit information. Otherwise it uses the low * level reflection APIs to study the target class and uses design patterns to * analyze its behaviour and then proceeds to continue the introspection with * its baseclass. *

*

* To look for the explicit information of a bean: *

* * The Introspector appends "BeanInfo" to the qualified name * of the bean class, try to use the new class as the "BeanInfo" class. If the * "BeanInfo" class exsits and returns non-null value when queried for explicit * information, use the explicit information * If the first step fails, the Introspector will extract a * simple class name of the bean class by removing the package name from the * qualified name of the bean class, append "BeanInfo" to it. And look for the * simple class name in the packages defined in the "BeanInfo" search path (The * default "BeanInfo" search path is sun.beans.infos). If it * finds a "BeanInfo" class and the "BeanInfo" class returns non-null value when * queried for explicit information, use the explicit information * * */ //ScrollPane cannot be introspected correctly public class Introspector extends java.lang.Object { // Public fields /** * Constant values to indicate that the Introspector will * ignore all BeanInfo class. */ public static final int IGNORE_ALL_BEANINFO = 3; /** * Constant values to indicate that the Introspector will * ignore the BeanInfo class of the current bean class. */ public static final int IGNORE_IMMEDIATE_BEANINFO = 2; /** * Constant values to indicate that the Introspector will use * all BeanInfo class which have been found. This is the default one. */ public static final int USE_ALL_BEANINFO = 1; // Default search path for BeanInfo classes private static final String DEFAULT_BEANINFO_SEARCHPATH = "sun.beans.infos"; //$NON-NLS-1$ // The search path to use to find BeanInfo classes // - an array of package names that are used in turn private static String[] searchPath = { DEFAULT_BEANINFO_SEARCHPATH }; // The cache to store Bean Info objects that have been found or created private static final int DEFAULT_CAPACITY = 128; private static Map, StandardBeanInfo> theCache = Collections.synchronizedMap(new WeakHashMap, StandardBeanInfo>(DEFAULT_CAPACITY)); private Introspector() { super(); } /** * Decapitalizes a given string according to the rule: * * If the first or only character is Upper Case, it is made Lower Case * UNLESS the second character is also Upper Case, when the String is * returned unchanged * * @param name - * the String to decapitalize * @return the decapitalized version of the String */ public static String decapitalize(String name) { if (name == null) return null; // The rule for decapitalize is that: // If the first letter of the string is Upper Case, make it lower case // UNLESS the second letter of the string is also Upper Case, in which case no // changes are made. if (name.length() == 0 || (name.length() > 1 && Character.isUpperCase(name.charAt(1)))) { return name; } char[] chars = name.toCharArray(); chars[0] = Character.toLowerCase(chars[0]); return new String(chars); } /** * Flushes all BeanInfo caches. * */ public static void flushCaches() { // Flush the cache by throwing away the cache HashMap and creating a // new empty one theCache.clear(); } /** * Flushes the BeanInfo caches of the specified bean class * * @param clazz * the specified bean class */ public static void flushFromCaches(Class clazz) { if(clazz == null){ throw new NullPointerException(); } theCache.remove(clazz); } /** * Gets the BeanInfo object which contains the information of * the properties, events and methods of the specified bean class. * *

* The Introspector will cache the BeanInfo * object. Subsequent calls to this method will be answered with the cached * data. *

* * @param beanClass * the specified bean class. * @return the BeanInfo of the bean class. * @throws IntrospectionException exception */ public static BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { StandardBeanInfo beanInfo = theCache.get(beanClass); if (beanInfo == null) { beanInfo = getBeanInfoImplAndInit(beanClass, null, USE_ALL_BEANINFO); theCache.put(beanClass, beanInfo); } return beanInfo; } /** * Gets the BeanInfo object which contains the information of * the properties, events and methods of the specified bean class. It will * not introspect the "stopclass" and its super class. * *

* The Introspector will cache the BeanInfo * object. Subsequent calls to this method will be answered with the cached * data. *

* * @param beanClass * the specified beanClass. * @param stopClass * the sopt class which should be super class of the bean class. * May be null. * @return the BeanInfo of the bean class. * @throws IntrospectionException exception */ public static BeanInfo getBeanInfo(Class beanClass, Class stopClass) throws IntrospectionException { if(stopClass == null){ //try to use cache return getBeanInfo(beanClass); } return getBeanInfoImplAndInit(beanClass, stopClass, USE_ALL_BEANINFO); } /** * Gets the BeanInfo object which contains the information of * the properties, events and methods of the specified bean class. * * If flag==IGNORE_ALL_BEANINFO, the * Introspector will ignore all BeanInfo * class. * If flag==IGNORE_IMMEDIATE_BEANINFO, the * Introspector will ignore the BeanInfo class * of the current bean class. * If flag==USE_ALL_BEANINFO, the * Introspector will use all BeanInfo class * which have been found. * *

* The Introspector will cache the BeanInfo * object. Subsequent calls to this method will be answered with the cached * data. *

* * @param beanClass * the specified bean class. * @param flags * the flag to control the usage of the explicit * BeanInfo class. * @return the BeanInfo of the bean class. * @throws IntrospectionException exception */ public static BeanInfo getBeanInfo(Class beanClass, int flags) throws IntrospectionException { if(flags == USE_ALL_BEANINFO){ //try to use cache return getBeanInfo(beanClass); } return getBeanInfoImplAndInit(beanClass, null, flags); } /** * Gets an array of search packages. * * @return an array of search packages. */ public static String[] getBeanInfoSearchPath() { String[] path = new String[searchPath.length]; System.arraycopy(searchPath, 0, path, 0, searchPath.length); return path; } /** * Sets the search packages. * * @param path the new search packages to be set. */ public static void setBeanInfoSearchPath(String[] path) { if (System.getSecurityManager() != null) { System.getSecurityManager().checkPropertiesAccess(); } searchPath = path; } private static StandardBeanInfo getBeanInfoImpl(Class beanClass, Class stopClass, int flags) throws IntrospectionException { BeanInfo explicitInfo = null; if (flags == USE_ALL_BEANINFO) { explicitInfo = getExplicitBeanInfo(beanClass); } StandardBeanInfo beanInfo = new StandardBeanInfo(beanClass, explicitInfo, stopClass); if (beanInfo.additionalBeanInfo != null) { for (int i = beanInfo.additionalBeanInfo.length-1; i >=0; i--) { BeanInfo info = beanInfo.additionalBeanInfo[i]; beanInfo.mergeBeanInfo(info, true); } } // recursive get beaninfo for super classes Class beanSuperClass = beanClass.getSuperclass(); if (beanSuperClass != stopClass) { if (beanSuperClass == null) throw new IntrospectionException( "Stop class is not super class of bean class"); //$NON-NLS-1$ int superflags = flags == IGNORE_IMMEDIATE_BEANINFO ? USE_ALL_BEANINFO : flags; BeanInfo superBeanInfo = getBeanInfoImpl(beanSuperClass, stopClass, superflags); if (superBeanInfo != null) { beanInfo.mergeBeanInfo(superBeanInfo, false); } } return beanInfo; } private static BeanInfo getExplicitBeanInfo(Class beanClass) { String beanInfoClassName = beanClass.getName() + "BeanInfo"; //$NON-NLS-1$ try { return loadBeanInfo(beanInfoClassName, beanClass); } catch (Exception e) { // fall through } int index = beanInfoClassName.lastIndexOf('.'); String beanInfoName = index >= 0 ? beanInfoClassName .substring(index + 1) : beanInfoClassName; BeanInfo theBeanInfo = null; BeanDescriptor beanDescriptor = null; for (int i = 0; i < searchPath.length; i++) { beanInfoClassName = searchPath[i] + "." + beanInfoName; //$NON-NLS-1$ try { theBeanInfo = loadBeanInfo(beanInfoClassName, beanClass); } catch (Exception e) { // ignore, try next one continue; } beanDescriptor = theBeanInfo.getBeanDescriptor(); if (beanDescriptor != null && beanClass == beanDescriptor.getBeanClass()) { return theBeanInfo; } } if (BeanInfo.class.isAssignableFrom(beanClass)) { try { return loadBeanInfo(beanClass.getName(), beanClass); } catch (Exception e) { // fall through } } return null; } /* * Method which attempts to instantiate a BeanInfo object of the supplied * classname * * @param theBeanInfoClassName - * the Class Name of the class of which the BeanInfo is an * instance * @param classLoader * @return A BeanInfo object which is an instance of the Class named * theBeanInfoClassName null if the Class does not exist or if there * are problems instantiating the instance */ private static BeanInfo loadBeanInfo(String beanInfoClassName, Class beanClass) throws Exception{ try { ClassLoader cl = beanClass.getClassLoader(); if(cl != null){ return (BeanInfo) Class.forName(beanInfoClassName, true, beanClass.getClassLoader()).newInstance(); } } catch (Exception e) { // fall through } try { return (BeanInfo) Class.forName(beanInfoClassName, true, ClassLoader.getSystemClassLoader()).newInstance(); } catch (Exception e) { // fall through } return (BeanInfo) Class.forName(beanInfoClassName, true, Thread.currentThread().getContextClassLoader()).newInstance(); } private static StandardBeanInfo getBeanInfoImplAndInit(Class beanClass, Class stopClass, int flag) throws IntrospectionException { StandardBeanInfo standardBeanInfo = getBeanInfoImpl(beanClass, stopClass, flag); standardBeanInfo.init(); return standardBeanInfo; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy