code: private _PropertyDescriptorHolder getPropertyDescriptor(String key)
      {
          if (_propertyDescriptorMap == null)
          {
              // Try to get descriptor map from cache
              _propertyDescriptorMap = propertyDescriptorCache.get(_component.getClass());
              // Cache miss: create descriptor map and put it in cache
              if (_propertyDescriptorMap == null)
              {
                  // Create descriptor map...
                  BeanInfo beanInfo;
                  try
                  {
                      beanInfo = Introspector.getBeanInfo(_component.getClass());
                  }
                  catch (IntrospectionException e)
                  {
                      throw new FacesException(e);
                  }
                  PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                  _propertyDescriptorMap = new ConcurrentHashMap<String, _PropertyDescriptorHolder>();
                  for (int i = 0; i < propertyDescriptors.length; i++)
                  {
                      PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
                      Method readMethod = propertyDescriptor.getReadMethod();
                      if (readMethod != null)
                      {
                          _propertyDescriptorMap.put(propertyDescriptor.getName(),
                                  new _PropertyDescriptorHolder(propertyDescriptor, readMethod));
                      }
                  }
                  // ... and put it in cache
                  synchronized(propertyDescriptorCache)
                  {
                      // Use a synchronized block to ensure proper operation on concurrent use cases.
                      // This is a racy single check, because initialization over the same class could happen
                      // multiple times, but the same result is always calculated. The synchronized block 
                      // just ensure thread-safety, because only one thread will modify the cache map
                      // at the same time.
                      propertyDescriptorCache.put(_component.getClass(), _propertyDescriptorMap);
                  }
              }
          }
          return _propertyDescriptorMap.get(key);
      }
docs: Retrieve info about getter/setter methods for the javabean property
  of the specified name on the underlying UIComponent object.
  <p/>
  This method optimises access to javabean properties of the underlying
  UIComponent by maintaining a cache of ProperyDescriptor objects for
  that class.
  <p/>
  TODO: Consider making the cache shared between component instances;
  currently 100 UIInputText components means performing introspection
  on the UIInputText component 100 times.