我如何获得嵌套属性的方法?

时间:2010-12-27 22:02:02

标签: java reflection javabeans

我有一个类Foo,它是Bar。

类型的属性
public class Foo {
    public Bar getBar() {

    }
}

public class Bar {
    public String getName();
}

是否有帮助程序类或方法使用java.lang.reflect.Method和“bar.name”来获取Bar名称属性的Foo.class对象?

Commons BeanUtils中有一个名为PropertyUtils的类,但其getPropertyDescriptor()仅适用于Object个实例,而不适用于Class个实例。

我意识到实施一个并不难,但我想利用现有的功能。

另外,我需要一个Method对象的事实不是糟糕设计的结果(希望不是)。我正在研究的几乎是JavaBeans编辑器。

谢谢!

5 个答案:

答案 0 :(得分:2)

在这里你可以寻找嵌套支持: 根据用例,可以缓存检索到的类。例如,在使用重过滤的数据表crud应用程序中。

/**
 * Retrieves the type of the property with the given name of the given
 * Class.<br>
 * Supports nested properties following bean naming convention.
 * 
 * "foo.bar.name"
 * 
 * @see PropertyUtils#getPropertyDescriptors(Class)
 * 
 * @param clazz
 * @param propertyName
 * 
 * @return Null if no property exists.
 */
public static Class<?> getPropertyType(Class<?> clazz, String propertyName)
{
    if (clazz == null)
        throw new IllegalArgumentException("Clazz must not be null.");
    if (propertyName == null)
        throw new IllegalArgumentException("PropertyName must not be null.");

    final String[] path = propertyName.split("\\.");

    for (int i = 0; i < path.length; i++)
    {
        propertyName = path[i];
        final PropertyDescriptor[] propDescs = PropertyUtils.getPropertyDescriptors(clazz);
        for (final PropertyDescriptor propDesc : propDescs)
            if (propDesc.getName().equals(propertyName))
            {
                clazz = propDesc.getPropertyType();
                if (i == path.length - 1)
                    return clazz;
            }
    }

    return null;
}

答案 1 :(得分:1)

在Commons BeanUtils中,PropertyUtils.getPropertyDescriptors()Class作为输入并返回PropertyDescriptor数组。

我不知道它是否会返回“嵌套”名称,例如bar.name,但如果没有,则不应该太难以对结果进行递归并构建自己的嵌套名称列表。

只是快速进行健全检查......世界真的需要另一个JavaBeans编辑器吗?

答案 2 :(得分:1)

我会使用MVEL或OGNL并跳过“我需要方法对象”的要求。

答案 3 :(得分:0)

这是djmj answer的一个版本,如果有人感兴趣,Java 8流将返回Optional。

/**
 * Retrieves the type of the property with the given name of the given Class.
 *
 * Supports nested properties following bean naming convention "foo.bar.name"
 *
 * @return Optional.empty if no property exists.
 * @see PropertyUtils#getPropertyDescriptors(Class)
 */
public static Optional<Class<?>> findPropertyType(@NotNull Class<?> clazz, @NotBlank String propertyName) {
  return Arrays.stream(propertyName.split("\\.")).reduce(
      Optional.ofNullable(clazz), // identity -> initial value of the accumulator
      (Optional<Class<?>> accOptClazz, String nextPropertyName) -> // accumulator with current value and next value from string
          stream(accOptClazz)
              .map((Class<?> accClazz) -> Arrays.stream(PropertyUtils.getPropertyDescriptors(accClazz)))
              .flatMap(Function.identity())
              .filter(propDesc -> propDesc.getName().equals(nextPropertyName))
              .findFirst().map(PropertyDescriptor::getPropertyType),
      (clazzA, clazzB) -> null // needed but useless combiner (only for parallel reduce)
  );
}

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon whether a value is present.
 */
public static <T> Stream<T> stream(Optional<T> opt) {
  return opt.isPresent() ? Stream.of(opt.get()) : Stream.empty();
}

答案 4 :(得分:0)

通过尝试将 Spring Data Sort 转换为 Comparator 到这里。

public class ComparatorUtils {
    public static <T> Comparator<T> fromSort(Sort sort, Class<T> type) {
        final Iterator<Sort.Order> orderIterator = sort.iterator();
        final Sort.Order order = orderIterator.next();

        Comparator<T> comparator = fromSortOrder(order, type);
        while (orderIterator.hasNext()) {
            comparator = comparator.thenComparing(fromSortOrder(orderIterator.next(), type));
        }

        return comparator;
    }

    private static <T> Comparator<T> fromSortOrder(Sort.Order order, Class<T> type) {
        final List<Method> accessMethods = new ArrayList<>();
        Class<?> currentClass = type;

        for (String property : order.getProperty().split("\\.")) {
            Method m = Objects.requireNonNull(BeanUtils.getPropertyDescriptor(currentClass, property)).getReadMethod();
            accessMethods.add(m);
            currentClass = m.getReturnType();
        }

        Comparator<T> comparator = Comparator.comparing((T entity) -> {
            try {
                Object result = entity;
                for (Method method : accessMethods) {
                    result = method.invoke(result);
                }
                return (Comparable) result;
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }, Comparator.nullsLast(Comparator.naturalOrder()));

        if (order.isDescending())
            return comparator.reversed();
        return comparator;
    }
}