Exemple #1
0
  /**
   * There are some nasty bugs for introspection with generics. This method addresses those nasty
   * bugs and tries to find proper methods if available
   * http://bugs.sun.com/view_bug.do?bug_id=6788525 http://bugs.sun.com/view_bug.do?bug_id=6528714
   *
   * @param descriptor
   * @return
   */
  private static PropertyDescriptor fixGenericDescriptor(
      Class<?> clazz, PropertyDescriptor descriptor) {
    Method readMethod = descriptor.getReadMethod();
    Method writeMethod = descriptor.getWriteMethod();

    if (readMethod != null && (readMethod.isBridge() || readMethod.isSynthetic())) {
      String propertyName = descriptor.getName();
      // capitalize the first letter of the string;
      String baseName = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
      String setMethodName = "set" + baseName;
      String getMethodName = "get" + baseName;
      Method[] methods = clazz.getMethods();
      for (Method method : methods) {
        if (method.getName().equals(getMethodName) && !method.isBridge() && !method.isSynthetic()) {
          try {
            descriptor.setReadMethod(method);
          } catch (IntrospectionException e) {
            // move on
          }
        }
        if (method.getName().equals(setMethodName) && !method.isBridge() && !method.isSynthetic()) {
          try {
            descriptor.setWriteMethod(method);
          } catch (IntrospectionException e) {
            // move on
          }
        }
      }
    }
    return descriptor;
  }
  /**
   * Gets the method that should be used to read the property value.
   *
   * @return The method that should be used to read the property value. May return null if the
   *     property can't be read.
   */
  public synchronized Method getReadMethod() {
    Method readMethod = getReadMethod0();
    if (readMethod == null) {
      Class cls = getClass0();
      if (cls == null || (readMethodName == null && readMethodRef == null)) {
        // The read method was explicitly set to null.
        return null;
      }
      if (readMethodName == null) {
        Class type = getPropertyType0();
        if (type == boolean.class || type == null) {
          readMethodName = "is" + getBaseName();
        } else {
          readMethodName = "get" + getBaseName();
        }
      }

      // Since there can be multiple write methods but only one getter
      // method, find the getter method first so that you know what the
      // property type is.  For booleans, there can be "is" and "get"
      // methods.  If an "is" method exists, this is the official
      // reader method so look for this one first.
      readMethod = Introspector.findMethod(cls, readMethodName, 0);
      if (readMethod == null) {
        readMethodName = "get" + getBaseName();
        readMethod = Introspector.findMethod(cls, readMethodName, 0);
      }
      try {
        setReadMethod(readMethod);
      } catch (IntrospectionException ex) {
        // fall
      }
    }
    return readMethod;
  }
 public static Map<String, PropertyDescriptor> propertyDescriptorsByName(
     final Class<?> beanClass) {
   final Map<String, PropertyDescriptor> map = new TreeMap<String, PropertyDescriptor>();
   for (Method method : beanClass.getMethods()) {
     final boolean readMethod = isReadMethod(method);
     final boolean writeMethod = !readMethod && isWriteMethod(method);
     //			LOGGER.debug("isReadMethod({}) => {}", method, readMethod);
     //			LOGGER.debug("isWriteMethod({}) => {}", method, writeMethod);
     if (!(readMethod || writeMethod)) {
       continue;
     }
     final String name = propertyName(method);
     LOGGER.debug("{} => {}", method, name);
     try {
       PropertyDescriptor descriptor = map.get(name);
       if (descriptor == null) {
         map.put(name, descriptor = new PropertyDescriptor(name, beanClass, null, null));
       }
       if (readMethod) {
         descriptor.setReadMethod(method);
       } else {
         descriptor.setWriteMethod(method);
       }
     } catch (IntrospectionException x) {
       throw new RuntimeException(x);
     }
   }
   return Collections.unmodifiableMap(map);
 }
 /**
  * This constructor takes the name of a simple property, and Method objects for reading and
  * writing the property.
  *
  * @param propertyName The programmatic name of the property.
  * @param readMethod The method used for reading the property value. May be null if the property
  *     is write-only.
  * @param writeMethod The method used for writing the property value. May be null if the property
  *     is read-only.
  * @exception IntrospectionException if an exception occurs during introspection.
  */
 public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
     throws IntrospectionException {
   if (propertyName == null || propertyName.length() == 0) {
     throw new IntrospectionException("bad property name");
   }
   setName(propertyName);
   setReadMethod(readMethod);
   setWriteMethod(writeMethod);
 }
 /**
  * Creates <code>PropertyDescriptor</code> for the specified bean with the specified name and
  * methods to read/write the property value.
  *
  * @param bean the type of the target bean
  * @param base the base name of the property (the rest of the method name)
  * @param read the method used for reading the property value
  * @param write the method used for writing the property value
  * @exception IntrospectionException if an exception occurs during introspection
  * @since 1.7
  */
 PropertyDescriptor(Class<?> bean, String base, @Nullable Method read, @Nullable Method write)
     throws IntrospectionException {
   if (bean == null) {
     throw new IntrospectionException("Target Bean class is null");
   }
   setClass0(bean);
   setName(Introspector.decapitalize(base));
   setReadMethod(read);
   setWriteMethod(write);
   this.baseName = base;
 }
Exemple #6
0
  static PropertyDescriptor[] getInterfacePropertyDescriptors(Class<?> interfaceClass) {
    List<PropertyDescriptor> propDescriptors = new ArrayList<PropertyDescriptor>();
    // Add prop descriptors for interface passed in
    propDescriptors.addAll(Arrays.asList(BeanUtils.getPropertyDescriptors(interfaceClass)));

    // Look for interface inheritance. If super interfaces are found, recurse up the hierarchy tree
    // and add prop
    // descriptors for each interface found.
    // PropertyUtils.getPropertyDescriptors() does not correctly walk the inheritance hierarchy for
    // interfaces.
    Class<?>[] interfaces = interfaceClass.getInterfaces();
    if (interfaces != null) {
      for (Class<?> superInterfaceClass : interfaces) {
        List<PropertyDescriptor> superInterfacePropertyDescriptors =
            Arrays.asList(getInterfacePropertyDescriptors(superInterfaceClass));
        /*
         * #1814758
         * Check for existing descriptor with the same name to prevent 2 property descriptors with the same name being added
         * to the result list.  This caused issues when getter and setter of an attribute on different interfaces in
         * an inheritance hierarchy
         */
        for (PropertyDescriptor superPropDescriptor : superInterfacePropertyDescriptors) {
          PropertyDescriptor existingPropDescriptor =
              findPropDescriptorByName(propDescriptors, superPropDescriptor.getName());
          if (existingPropDescriptor == null) {
            propDescriptors.add(superPropDescriptor);
          } else {
            try {
              if (existingPropDescriptor.getReadMethod() == null) {
                existingPropDescriptor.setReadMethod(superPropDescriptor.getReadMethod());
              }
              if (existingPropDescriptor.getWriteMethod() == null) {
                existingPropDescriptor.setWriteMethod(superPropDescriptor.getWriteMethod());
              }
            } catch (IntrospectionException e) {
              throw new MappingException(e);
            }
          }
        }
      }
    }
    return propDescriptors.toArray(new PropertyDescriptor[propDescriptors.size()]);
  }
  /**
   * Gets the method that should be used to read the property value.
   *
   * @return The method that should be used to read the property value. May return null if the
   *     property can't be read.
   */
  @Pure
  public synchronized @Nullable Method getReadMethod() {
    Method readMethod = this.readMethodRef.get();
    if (readMethod == null) {
      Class<?> cls = getClass0();
      if (cls == null || (readMethodName == null && !this.readMethodRef.isSet())) {
        // The read method was explicitly set to null.
        return null;
      }
      String nextMethodName = Introspector.GET_PREFIX + getBaseName();
      if (readMethodName == null) {
        Class<?> type = getPropertyType0();
        if (type == boolean.class || type == null) {
          readMethodName = Introspector.IS_PREFIX + getBaseName();
        } else {
          readMethodName = nextMethodName;
        }
      }

      // Since there can be multiple write methods but only one getter
      // method, find the getter method first so that you know what the
      // property type is.  For booleans, there can be "is" and "get"
      // methods.  If an "is" method exists, this is the official
      // reader method so look for this one first.
      readMethod = Introspector.findMethod(cls, readMethodName, 0);
      if ((readMethod == null) && !readMethodName.equals(nextMethodName)) {
        readMethodName = nextMethodName;
        readMethod = Introspector.findMethod(cls, readMethodName, 0);
      }
      try {
        setReadMethod(readMethod);
      } catch (IntrospectionException ex) {
        // fall
      }
    }
    return readMethod;
  }
  /**
   * Package-private constructor. Merge two property descriptors. Where they conflict, give the
   * second argument (y) priority over the first argument (x).
   *
   * @param x The first (lower priority) PropertyDescriptor
   * @param y The second (higher priority) PropertyDescriptor
   */
  PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
    super(x, y);

    if (y.baseName != null) {
      baseName = y.baseName;
    } else {
      baseName = x.baseName;
    }

    if (y.readMethodName != null) {
      readMethodName = y.readMethodName;
    } else {
      readMethodName = x.readMethodName;
    }

    if (y.writeMethodName != null) {
      writeMethodName = y.writeMethodName;
    } else {
      writeMethodName = x.writeMethodName;
    }

    if (y.propertyTypeRef != null) {
      propertyTypeRef = y.propertyTypeRef;
    } else {
      propertyTypeRef = x.propertyTypeRef;
    }

    // Figure out the merged read method.
    Method xr = x.getReadMethod();
    Method yr = y.getReadMethod();

    // Normally give priority to y's readMethod.
    try {
      if (yr != null && yr.getDeclaringClass() == getClass0()) {
        setReadMethod(yr);
      } else {
        setReadMethod(xr);
      }
    } catch (IntrospectionException ex) {
      // fall through
    }

    // However, if both x and y reference read methods in the same class,
    // give priority to a boolean "is" method over a boolean "get" method.
    if (xr != null
        && yr != null
        && xr.getDeclaringClass() == yr.getDeclaringClass()
        && xr.getReturnType() == boolean.class
        && yr.getReturnType() == boolean.class
        && xr.getName().indexOf("is") == 0
        && yr.getName().indexOf("get") == 0) {
      try {
        setReadMethod(xr);
      } catch (IntrospectionException ex) {
        // fall through
      }
    }

    Method xw = x.getWriteMethod();
    Method yw = y.getWriteMethod();

    try {
      if (yw != null && yw.getDeclaringClass() == getClass0()) {
        setWriteMethod(yw);
      } else {
        setWriteMethod(xw);
      }
    } catch (IntrospectionException ex) {
      // Fall through
    }

    if (y.getPropertyEditorClass() != null) {
      setPropertyEditorClass(y.getPropertyEditorClass());
    } else {
      setPropertyEditorClass(x.getPropertyEditorClass());
    }

    bound = x.bound | y.bound;
    constrained = x.constrained | y.constrained;
  }
  private void addOrUpdatePropertyDescriptor(
      String propertyName,
      Method readMethod,
      Method writeMethod,
      Method indexedReadMethod,
      Method indexedWriteMethod)
      throws IntrospectionException {
    for (PropertyDescriptor existingPD : this.propertyDescriptors) {
      if (existingPD.getName().equals(propertyName)) {
        // is there already a descriptor that captures this read method or its corresponding write
        // method?
        if (existingPD.getReadMethod() != null) {
          if (readMethod != null
                  && existingPD.getReadMethod().getReturnType() != readMethod.getReturnType()
              || writeMethod != null
                  && existingPD.getReadMethod().getReturnType()
                      != writeMethod.getParameterTypes()[0]) {
            // no -> add a new descriptor for it below
            break;
          }
        }
        // update the existing descriptor's read method
        if (readMethod != null) {
          try {
            existingPD.setReadMethod(readMethod);
          } catch (IntrospectionException ex) {
            // there is a conflicting setter method present -> null it out and try again
            existingPD.setWriteMethod(null);
            existingPD.setReadMethod(readMethod);
          }
        }

        // is there already a descriptor that captures this write method or its corresponding read
        // method?
        if (existingPD.getWriteMethod() != null) {
          if (readMethod != null
                  && existingPD.getWriteMethod().getParameterTypes()[0]
                      != readMethod.getReturnType()
              || writeMethod != null
                  && existingPD.getWriteMethod().getParameterTypes()[0]
                      != writeMethod.getParameterTypes()[0]) {
            // no -> add a new descriptor for it below
            break;
          }
        }
        // update the existing descriptor's write method
        if (writeMethod != null) {
          existingPD.setWriteMethod(writeMethod);
        }

        // is this descriptor indexed?
        if (existingPD instanceof IndexedPropertyDescriptor) {
          IndexedPropertyDescriptor existingIPD = (IndexedPropertyDescriptor) existingPD;

          // is there already a descriptor that captures this indexed read method or its
          // corresponding indexed write method?
          if (existingIPD.getIndexedReadMethod() != null) {
            if (indexedReadMethod != null
                    && existingIPD.getIndexedReadMethod().getReturnType()
                        != indexedReadMethod.getReturnType()
                || indexedWriteMethod != null
                    && existingIPD.getIndexedReadMethod().getReturnType()
                        != indexedWriteMethod.getParameterTypes()[1]) {
              // no -> add a new descriptor for it below
              break;
            }
          }
          // update the existing descriptor's indexed read method
          try {
            if (indexedReadMethod != null) {
              existingIPD.setIndexedReadMethod(indexedReadMethod);
            }
          } catch (IntrospectionException ex) {
            // there is a conflicting indexed setter method present -> null it out and try again
            existingIPD.setIndexedWriteMethod(null);
            existingIPD.setIndexedReadMethod(indexedReadMethod);
          }

          // is there already a descriptor that captures this indexed write method or its
          // corresponding indexed read method?
          if (existingIPD.getIndexedWriteMethod() != null) {
            if (indexedReadMethod != null
                    && existingIPD.getIndexedWriteMethod().getParameterTypes()[1]
                        != indexedReadMethod.getReturnType()
                || indexedWriteMethod != null
                    && existingIPD.getIndexedWriteMethod().getParameterTypes()[1]
                        != indexedWriteMethod.getParameterTypes()[1]) {
              // no -> add a new descriptor for it below
              break;
            }
          }
          // update the existing descriptor's indexed write method
          if (indexedWriteMethod != null) {
            existingIPD.setIndexedWriteMethod(indexedWriteMethod);
          }
        }

        // the descriptor has been updated -> return immediately
        return;
      }
    }

    // we haven't yet seen read or write methods for this property -> add a new descriptor
    if (indexedReadMethod == null && indexedWriteMethod == null) {
      this.propertyDescriptors.add(new PropertyDescriptor(propertyName, readMethod, writeMethod));
    } else {
      this.propertyDescriptors.add(
          new IndexedPropertyDescriptor(
              propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod));
    }
  }