【问题标题】:Java Reflection: How can I get the all getter methods of a java class and invoke themJava 反射:如何获取 java 类的所有 getter 方法并调用它们
【发布时间】:2012-01-21 09:07:44
【问题描述】:

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

【问题讨论】:

    标签: java reflection


    【解决方案1】:

    为什么不使用简单的 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;
    }
    

    ...

    【讨论】:

      【解决方案2】:

      这段代码测试OK。

      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();
              }
          }
      

      【讨论】:

      【解决方案3】:

      不要使用正则表达式,使用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 here) 就是这样做的:找到并执行所有的 getter 并将结果存储在一个映射中。不幸的是,BeanUtils.describe() 在返回之前将所有属性值转换为字符串。哇。谢谢@danw


      更新:

      这是一个基于对象的 bean 属性返回 Map&lt;String, Object&gt; 的 Java 8 方法。

      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);
          }
      }
      

      【讨论】:

      • 哇。我不知道你能做到这一点!酷!
      • 谢谢..我测试代码...输出的结尾是public final native java.lang.Class java.lang.Object.getClass().. .我不想调用它..如何删除它?
      • @user996505 使用 Introspector.getBeanInfo(yourClass, Object.class) ,搜索 Object 下面的所有类
      • 仅供参考,BeanUtils.describe(yourObject); 返回 Map&lt;String, String&gt; 而不是 Map`。
      • @RyanJ.McDonough 这是一个普通的 Java 问题,而不是 Android 问题。 Introspector 是标准 Java 的标准机制。 Android 可能有也可能没有不同的机制,但这并不会使我的答案无效
      【解决方案4】:

      Spring 为 Bean 内省提供了一个简单的 BeanUtil method

      PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property);
      Method getter = pd.getReadMethod();
      

      【讨论】:

        【解决方案5】:

        您可以为此使用Reflections 框架

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

        【讨论】:

        • 并非所有的getter都以“get”开头:(1)返回布尔值的getter可能以“is”开头; (2) BeanInfo 类可以声明附加方法是 getter。你真的应该添加一个限制,比如如果你知道你所有的getter都以“get”开头,你可以这样做
        【解决方案6】:
         // 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());
            }
        

        【讨论】:

        • 是的,但是您还必须检查每个方法是否是公共的、非静态的、返回 void、不需要参数并遵循 get/isXyz 名称约定。 Introspector 会为您完成所有这些工作,此外它还在内部为其他应用程序缓存 BeanInfo 数据。
        • 可以,但是如果你不想添加库怎么办,你在Android上需要它,例如,复制到这里。 docjar.com/html/api/java/beans/Introspector.java.html#511
        猜你喜欢
        • 1970-01-01
        • 2016-04-28
        • 2011-07-21
        • 2014-05-23
        • 1970-01-01
        • 2021-01-08
        • 2013-12-20
        • 2011-06-26
        相关资源
        最近更新 更多