2011-12-15 2 views
52

Я пишу класс java, у которого много геттеров. Теперь я хочу получить все методы getter и вызывать их когда-нибудь. Я знаю, что есть такие методы, как getMethods() или getMethod (String name, Class ... parameterTypes), но я просто хочу получить getter действительно ..., используйте regex? кто-нибудь может сказать мне? Спасибо!Java Reflection: Как я могу получить все методы getter класса java и вызывать их

ответ

128

Не следует использовать регулярное выражение, используйте 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 

BTW: есть рамки, которые делают это для вас и представляют вам вид на высоком уровне. Например. Обще/BeanUtils имеет метод

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

(docs here), который делает только что: найти и выполнить все методы получения и сохранения результата на карте. К сожалению, BeanUtils.describe() преобразует все значения свойств в строки перед возвратом. WTF. Благодаря @danw


Обновление:

Вот 8 метод Java, который возвращает Map<String, Object> на основе свойств компонента объекта.

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

Ничего себе. Я не знал, что ты можешь это сделать! Круто! –

+0

Спасибо ..и проверить код ... конец вывода ** общедоступный конечный родной java.lang.Class java.lang.Object.getClass() ** ... я не хочу его вызывать. Как его удалить? – user996505

+1

@ user996505 Используйте Introspector.getBeanInfo (yourClass, Object.class), чтобы искать все классы ниже. Объект –

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

Да, но вам также придется проверять каждый метод, что он является открытым, нестатическим, возвращает void, не ожидает никакого параметра и следует за соглашением имени get/isXyz. Introspector делает все это для вас, плюс он кэширует данные BeanInfo для других приложений. –

+0

не возвращает void, то есть –

16

Reflections каркас для этого

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

Не все геттеры начинаются с «get»: (1) boolean-возвращающиеся getters могут начинаться с «is»; (2) класс BeanInfo может утверждать, что дополнительные методы - это геттеры.Вы действительно должны добавить ограничение, например: если вы знаете, что все ваши получатели начинаются с «get», вы можете это сделать. – toolforger

-4

Вы должны поддерживать общий геттер в каждом компоненте, таким образом, чтобы вызвать getAttribute1(), вы должны иметь возможность ссылаться на общий геттер Get («attribute1»)

Этот общий добытчик будет в свою очередь Invoke правильный геттер

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

этот подход включает в себя вам сохранить этот отдельный список в каждом компоненте, но таким образом, вы избежать отражения, которая имеет проблемы с производительностью, так что если вы пишете производственный код, который нужно иметь хорошую производительность, вы можете использовать выше шаблон для всех ваших бобов.

Если это некий код кода или код полезности, который не имеет требований высокой производительности, тогда вам лучше использовать другие подходы, поскольку этот подход подвержен ошибкам, если вы не можете написать какой-то счетчик времени компиляции, который обеспечивает эту общую функцию getter работает для всех атрибутов.

7

Spring предлагает простой BeanUtil method для Bean самоанализа:

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

Этот код проверяется в порядке.

private void callAllGetterMethodsInTestModel(TestModel testModelObject) { 
     try { 
      Class testModelClass = Class.forName("com.encoders.eva.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(); 
     } 
    } 
Смежные вопросы