Java思考:如何获取Java类的所有getter方法并调用它们


72

我写了一个有很多getter的java类。现在我想获取所有getter方法并在某个时候调用它们。我知道有诸如getMethods()或getMethod(String name,Class ... parameterTypes)之类的方法,但是我只想确实获得吸气剂...,使用正则表达式?有人可以告诉我吗?

Answers:


162

不要使用正则表达式,请使用Introspector

for(PropertyDescriptor propertyDescriptor : 
    Introspector.getBeanInfo(yourClass).getPropertyDescriptors()){

    // propertyEditor.getReadMethod() exposes the getter
    // btw, this may be null if you have a write-only property
    System.out.println(propertyDescriptor.getReadMethod());
}

通常,您不需要Object.class的属性,因此可以使用带有两个参数的方法:

Introspector.getBeanInfo(yourClass, stopClass)
// usually with Object.class as 2nd param
// the first class is inclusive, the second exclusive

顺便说一句:有一些框架可以为您做到这一点,并向您展示高层次的观点。例如commons / beanutils有方法

Map<String, String> properties = BeanUtils.describe(yourObject);

docs此处)就是这样做的:查找并执行所有getter并将结果存储在地图中。不幸的是,BeanUtils.describe()在返回之前将所有属性值转换为字符串。WTF。谢谢@danw


更新:

这是一个Java 8方法,它Map<String, Object>根据对象的bean属性返回a 。

public static Map<String, Object> beanProperties(Object bean) {
  try {
    return Arrays.asList(
         Introspector.getBeanInfo(bean.getClass(), Object.class)
                     .getPropertyDescriptors()
      )
      .stream()
      // filter out properties with setters only
      .filter(pd -> Objects.nonNull(pd.getReadMethod()))
      .collect(Collectors.toMap(
        // bean property name
        PropertyDescriptor::getName,
        pd -> { // invoke method to get value
            try { 
                return pd.getReadMethod().invoke(bean);
            } catch (Exception e) {
                // replace this with better error handling
               return null;
            }
        }));
  } catch (IntrospectionException e) {
    // and this, too
    return Collections.emptyMap();
  }
}

不过,您可能想使错误处理更可靠。很抱歉,已检查的异常阻止我们在此无法正常运行。


事实证明Collectors.toMap()讨厌空值。这是上述代码的更命令性版本:

public static Map<String, Object> beanProperties(Object bean) {
    try {
        Map<String, Object> map = new HashMap<>();
        Arrays.asList(Introspector.getBeanInfo(bean.getClass(), Object.class)
                                  .getPropertyDescriptors())
              .stream()
              // filter out properties with setters only
              .filter(pd -> Objects.nonNull(pd.getReadMethod()))
              .forEach(pd -> { // invoke method to get value
                  try {
                      Object value = pd.getReadMethod().invoke(bean);
                      if (value != null) {
                          map.put(pd.getName(), value);
                      }
                  } catch (Exception e) {
                      // add proper error handling here
                  }
              });
        return map;
    } catch (IntrospectionException e) {
        // and here, too
        return Collections.emptyMap();
    }
}

使用JavaSlang,以更简洁的方式提供了相同的功能:

public static Map<String, Object> javaSlangBeanProperties(Object bean) {
    try {
        return Stream.of(Introspector.getBeanInfo(bean.getClass(), Object.class)
                                     .getPropertyDescriptors())
                     .filter(pd -> pd.getReadMethod() != null)
                     .toJavaMap(pd -> {
                         try {
                             return new Tuple2<>(
                                     pd.getName(),
                                     pd.getReadMethod().invoke(bean));
                         } catch (Exception e) {
                             throw new IllegalStateException();
                         }
                     });
    } catch (IntrospectionException e) {
        throw new IllegalStateException();

    }
}

这是番石榴的版本:

public static Map<String, Object> guavaBeanProperties(Object bean) {
    Object NULL = new Object();
    try {
        return Maps.transformValues(
                Arrays.stream(
                        Introspector.getBeanInfo(bean.getClass(), Object.class)
                                    .getPropertyDescriptors())
                      .filter(pd -> Objects.nonNull(pd.getReadMethod()))
                      .collect(ImmutableMap::<String, Object>builder,
                               (builder, pd) -> {
                                   try {
                                       Object result = pd.getReadMethod()
                                                         .invoke(bean);
                                       builder.put(pd.getName(),
                                                   firstNonNull(result, NULL));
                                   } catch (Exception e) {
                                       throw propagate(e);
                                   }
                               },
                               (left, right) -> left.putAll(right.build()))
                      .build(), v -> v == NULL ? null : v);
    } catch (IntrospectionException e) {
        throw propagate(e);
    }
}

6
哇。我不知道你能做到!凉!
科迪S

谢谢..i测试代码...输出的结尾是public final native java.lang.Class java.lang.Object.getClass() ...我不想调用它..如何删除它?
user996505 2011年

1
@ user996505使用Introspector.getBeanInfo(yourClass,Object.class),搜索对象以下的所有类
Sean Patrick Floyd

仅供参考,不BeanUtils.describe(yourObject);返回Map<String, String>Map <String,Object>`。
danw

1
@ RyanJ.McDonough这是一个简单的Java问题,而不是Android问题。内省器是用于标准Java的标准机制。Android可能有不同的机制,但这并没有使我的答案无效
Sean Patrick Floyd

23

您可以为此使用Reflections框架

import org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));

6
并非所有吸气剂都以“ get”开头:(1)返回布尔值的吸气剂可以以“ is”开头;(2)BeanInfo类可以声明其他方法是getter。您确实应该添加一个限制,例如,如果您知道所有吸气剂都以“ get”开头,则可以这样做
toolforger


9
 // Get the Class object associated with this class.
    MyClass myClass= new MyClass ();
    Class objClass= myClass.getClass();

    // Get the public methods associated with this class.
    Method[] methods = objClass.getMethods();
    for (Method method:methods)
    {
        System.out.println("Public method found: " +  method.toString());
    }

3
是的,但是您还必须检查每个方法是否公开,非静态,返回void,不包含任何参数并遵循get / isXyz名称约定。Introspector会为您完成所有这些工作,此外还会在内部为其他应用程序缓存BeanInfo数据。
肖恩·帕特里克·弗洛伊德

0

此代码已通过测试。

private void callAllGetterMethodsInTestModel(TestModel testModelObject) {
        try {
            Class testModelClass = Class.forName("com.example.testreflectionapi.TestModel");
            Method[] methods = testModelClass.getDeclaredMethods();
            ArrayList<String> getterResults = new ArrayList<>();
            for (Method method :
                    methods) {
                if (method.getName().startsWith("get")){
                    getterResults.add((String) method.invoke(testModelObject));
                }
            }
            Log.d("sayanReflextion", "==>: "+getterResults.toString());
        } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

抱歉,这是一种糟糕的方法。仅仅因为一个方法开始get并不意味着它就是一个吸气剂。
Madbreaks

0

为什么不使用简单的Java?...

public static Map<String, Object> beanProperties(final Object bean) {
    final Map<String, Object> result = new HashMap<String, Object>();

    try {
        final PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(bean.getClass(), Object.class).getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            final Method readMethod = propertyDescriptor.getReadMethod();
            if (readMethod != null) {
                result.put(propertyDescriptor.getName(), readMethod.invoke(bean, (Object[]) null));
            }
        }
    } catch (Exception ex) {
        // ignore
    }

    return result;
}

...


-5

您应该在每个bean中维护一个通用的getter,以便调用getAttribute1()您应该能够调用一个通用的getter get(“ Attribute1”)

这个通用的吸气剂将依次调用正确的吸气剂

Object get(String attribute)
{
    if("Attribute1".equals(attribute)
    {
        return getAttribute1();
    }
}

这种方法需要您在每个bean中维护这个单独的列表,但是这样可以避免出现性能问题的反思,因此,如果编写需要良好性能的生产代码,则可以对所有bean使用上述模式。

如果是一些不具有高性能要求的测试代码或实用程序代码,则最好采用其他方法,因为这种方法容易出错,除非您可以编写某种编译时间检查器以确保该通用getter函数对所有属性都有效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.