gt:         U lookup(ClassReflectionIndex index);
context: /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2011, Red Hat, Inc., and individual contributors
   * as indicated by the @author tags. See the copyright.txt file in the
   * distribution for a full listing of individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
   * published by the Free Software Foundation; either version 2.1 of
   * the License, or (at your option) any later version.
   *
   * This software is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  
  package org.jboss.as.pojo.service;
  
  import org.jboss.as.pojo.logging.PojoLogger;
  import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
  import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;
  
  /**
   * Default bean info.
   *
   * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
   */
  @SuppressWarnings({"unchecked"})
  public class DefaultBeanInfo<T> implements BeanInfo<T> {
      private final List<ClassReflectionIndex> indexes = new ArrayList<ClassReflectionIndex>();
      private final Class beanClass;
      private DeploymentReflectionIndex index;
      private Class currentClass;
  
      public DefaultBeanInfo(DeploymentReflectionIndex index, Class<T> beanClass) {
          this.index = index;
          this.beanClass = beanClass;
          this.currentClass = beanClass;
      }
  
      /**
       * Do lazy lookup.
       *
       * @param lookup the lookup
       * @param start the start
       * @param depth the depth
       * @return reflection index result
       */
      protected <U> U lookup(Lookup<U> lookup, int start, int depth) {
          int size;
          synchronized (indexes) {
              size = indexes.size();
              for (int i = start; i < depth && i < size; i++) {
                  U result = lookup.lookup(indexes.get(i));
                  if (result != null)
                      return result;
              }
          }
  
          if (currentClass == null)
              return null;
  
          synchronized (indexes) {
              ClassReflectionIndex cri = index.getClassIndex(currentClass);
              indexes.add(cri);
              currentClass = currentClass.getSuperclass();
          }
          return lookup(lookup, size, depth);
      }
  
      public Constructor<T> getConstructor(final String... parameterTypes) {
          return lookup(
                  new Lookup<Constructor<T>>() {
                      public Constructor<T> lookup(ClassReflectionIndex index) {
                          final Constructor ctor = index.getConstructor(parameterTypes);
                          if (ctor == null)
                              throw PojoLogger.ROOT_LOGGER.ctorNotFound(Arrays.toString(parameterTypes), beanClass.getName());
                          return ctor;
                      }
                  }, 0, 1);
      }
  
      @Override
      public Constructor<T> findConstructor(final String... parameterTypes) {
          return lookup(new Lookup<Constructor<T>>() {
              @Override
              public Constructor<T> lookup(ClassReflectionIndex index) {
                  final Collection<Constructor<?>> ctors = index.getConstructors();
                  for (Constructor c : ctors) {
                      if (Configurator.equals(parameterTypes, c.getParameterTypes()))
                          return c;
                  }
                  throw PojoLogger.ROOT_LOGGER.ctorNotFound(Arrays.toString(parameterTypes), beanClass.getName());
              }
          }, 0, 1);
      }
  
      @Override
      public Field getField(final String name) {
          final Field lookup = lookup(new Lookup<Field>() {
              @Override
              public Field lookup(ClassReflectionIndex index) {
                  return index.getField(name);
              }
          }, 0, Integer.MAX_VALUE);
          if (lookup == null)
              throw PojoLogger.ROOT_LOGGER.fieldNotFound(name, beanClass.getName());
          return lookup;
      }
  
      @Override
      public Method getMethod(final String name, final String... parameterTypes) {
          final Method lookup = lookup(new Lookup<Method>() {
              @Override
              public Method lookup(ClassReflectionIndex index) {
                  Collection<Method> methods = index.getMethods(name, parameterTypes);
                  int size = methods.size();
                  switch (size) {
                      case 0:
                          return null;
                      case 1:
                          return methods.iterator().next();
                      default:
                          throw PojoLogger.ROOT_LOGGER.ambiguousMatch(methods, name, beanClass.getName());
                  }
              }
          }, 0, Integer.MAX_VALUE);
          if (lookup == null)
              throw PojoLogger.ROOT_LOGGER.methodNotFound(name, Arrays.toString(parameterTypes), beanClass.getName());
          return lookup;
      }
  
      @Override
      public Method findMethod(String name, String... parameterTypes) {
          return Configurator.findMethod(index, beanClass, name, parameterTypes, false, true, true);
      }
  
      @Override
      public Method getGetter(final String propertyName, final Class<?> type) {
          final boolean isBoolean = Boolean.TYPE.equals(type);
          final String name = ((isBoolean) ? "is" : "get") + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
          final Method result = lookup(new Lookup<Method>() {
              @Override
              public Method lookup(ClassReflectionIndex index) {
                  Collection<Method> methods = index.getAllMethods(name, 0);
                  if (type == null) {
                      if (methods.size() == 1)
                          return methods.iterator().next();
                      else
                          return null;
                  }
                  for (Method m : methods) {
                      Class<?> pt = m.getReturnType();
                      if (pt.isAssignableFrom(type))
                          return m;
                  }
                  return null;
              }
          }, 0, Integer.MAX_VALUE);
          if (result == null)
              throw PojoLogger.ROOT_LOGGER.getterNotFound(type, beanClass.getName());
          return result;
      }
  
      @Override
      public Method getSetter(final String propertyName, final Class<?> type) {
          final String name = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
          final Method result = lookup(new Lookup<Method>() {
              @Override
              public Method lookup(ClassReflectionIndex index) {
                  Collection<Method> methods = index.getAllMethods(name, 1);
                  if (type == null) {
                      if (methods.size() == 1)
                          return methods.iterator().next();
                      else
                          return null;
                  }
                  for (Method m : methods) {
                      Class<?> pt = m.getParameterTypes()[0];
                      if (pt.isAssignableFrom(type))
                          return m;
                  }
                  return null;
              }
          }, 0, Integer.MAX_VALUE);
          if (result == null)
              throw PojoLogger.ROOT_LOGGER.setterNotFound(type, beanClass.getName());
          return result;
      }
  
      private interface Lookup<U> {
  