Ejemplo n.º 1
0
 private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
   int nParams = method.getParameterTypes().length;
   String propertyName = propertyNameFor(method);
   Class<?> propertyType = method.getParameterTypes()[nParams - 1];
   PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType);
   if (nParams == 1) {
     if (existingPd == null) {
       this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method));
     } else {
       existingPd.setWriteMethod(method);
     }
   } else if (nParams == 2) {
     if (existingPd == null) {
       this.propertyDescriptors.add(
           new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
     } else if (existingPd instanceof IndexedPropertyDescriptor) {
       ((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method);
     } else {
       this.propertyDescriptors.remove(existingPd);
       this.propertyDescriptors.add(
           new SimpleIndexedPropertyDescriptor(
               propertyName,
               existingPd.getReadMethod(),
               existingPd.getWriteMethod(),
               null,
               method));
     }
   } else {
     throw new IllegalArgumentException(
         "Write method must have exactly 1 or 2 parameters: " + method);
   }
 }
Ejemplo n.º 2
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;
  }
Ejemplo n.º 3
0
 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);
 }
Ejemplo n.º 4
0
 /**
  * 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);
 }
Ejemplo n.º 5
0
 /**
  * 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;
 }
Ejemplo n.º 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()]);
  }
Ejemplo n.º 7
0
  /**
   * Gets the method that should be used to write the property value.
   *
   * @return The method that should be used to write the property value. May return null if the
   *     property can't be written.
   */
  @Pure
  public synchronized @Nullable Method getWriteMethod() {
    Method writeMethod = this.writeMethodRef.get();
    if (writeMethod == null) {
      Class<?> cls = getClass0();
      if (cls == null || (writeMethodName == null && !this.writeMethodRef.isSet())) {
        // The write method was explicitly set to null.
        return null;
      }

      // We need the type to fetch the correct method.
      Class<?> type = getPropertyType0();
      if (type == null) {
        try {
          // Can't use getPropertyType since it will lead to recursive loop.
          type = findPropertyType(getReadMethod(), null);
          setPropertyType(type);
        } catch (IntrospectionException ex) {
          // Without the correct property type we can't be guaranteed
          // to find the correct method.
          return null;
        }
      }

      if (writeMethodName == null) {
        writeMethodName = Introspector.SET_PREFIX + getBaseName();
      }

      Class<?>[] args = (type == null) ? null : new Class<?>[] {type};
      writeMethod = Introspector.findMethod(cls, writeMethodName, 1, args);
      if (writeMethod != null) {
        if (!writeMethod.getReturnType().equals(void.class)) {
          writeMethod = null;
        }
      }
      try {
        setWriteMethod(writeMethod);
      } catch (IntrospectionException ex) {
        // fall through
      }
    }
    return writeMethod;
  }
Ejemplo n.º 8
0
  /**
   * Gets the method that should be used to write the property value.
   *
   * @return The method that should be used to write the property value. May return null if the
   *     property can't be written.
   */
  public synchronized Method getWriteMethod() {
    Method writeMethod = getWriteMethod0();
    if (writeMethod == null) {
      Class cls = getClass0();
      if (cls == null || (writeMethodName == null && writeMethodRef == null)) {
        // The write method was explicitly set to null.
        return null;
      }

      // We need the type to fetch the correct method.
      Class type = getPropertyType0();
      if (type == null) {
        try {
          // Can't use getPropertyType since it will lead to recursive loop.
          type = findPropertyType(getReadMethod(), null);
          setPropertyType(type);
        } catch (IntrospectionException ex) {
          // Without the correct property type we can't be guaranteed
          // to find the correct method.
          return null;
        }
      }

      if (writeMethodName == null) {
        writeMethodName = "set" + getBaseName();
      }

      writeMethod =
          Introspector.findMethod(
              cls, writeMethodName, 1, (type == null) ? null : new Class[] {type});
      try {
        setWriteMethod(writeMethod);
      } catch (IntrospectionException ex) {
        // fall through
      }
    }
    return writeMethod;
  }
  @Override
  public void introspect(IntrospectionContext context) throws IntrospectionException {
    for (Method method : context.getTargetClass().getMethods()) {
      try {
        Class<?>[] argTypes = method.getParameterTypes();
        int argCount = argTypes.length;
        if (argCount == 1 && method.getName().startsWith("set")) {
          String propertyName = Introspector.decapitalize(method.getName().substring(3));
          if (!propertyName.equals("class")) {
            PropertyDescriptor pd = context.getDescriptor(propertyName);
            boolean setWriteMethod = false;
            if (pd == null) {
              pd = new PropertyDescriptor(propertyName, null, method);
              context.addDescriptor(pd);
              setWriteMethod = true;
            } else if (pd.getWriteMethod() == null
                && pd.getReadMethod() != null
                && pd.getReadMethod().getReturnType() == argTypes[0]) {

              pd.setWriteMethod(method);
              setWriteMethod = true;
            }
            if (setWriteMethod) {
              for (Class<?> type : method.getExceptionTypes()) {
                if (type == PropertyVetoException.class) {
                  pd.setConstrained(true);
                  break;
                }
              }
            }
          }
        }
      } catch (IntrospectionException ignored) {
      }
    }
  }
Ejemplo n.º 10
0
  /**
   * 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;
  }
Ejemplo n.º 11
0
  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));
    }
  }