Отражение Java: как я могу получить все методы getter класса java и вызвать их
Я пишу класс java, который имеет много геттеров..теперь я хочу получить все методы getter и вызвать их когда-нибудь..Я знаю, что есть такие методы, как getMethods() или getMethod(String name, Class... parameterTypes), но я просто хочу получить геттер действительно...- использовать регулярное выражение? кто-нибудь может мне сказать ?Спасибо!
6 ответов:
не используйте регулярное выражение, используйте
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()); }обычно вы не хотите, чтобы свойства объекта.класс, поэтому вы бы использовали метод с двумя параметрами:
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);(документы здесь), которая делает именно это: найти и выполнить все геттеры и сохранить результат в карте. К сожалению,
BeanUtils.describe()преобразует все значения свойств в строки, прежде чем вернуться. КАКОГО ЧЕРТА. Спасибо @danw
обновление:
вот Java 8 метод, который возвращает
Map<String, Object>на основе свойств объекта bean.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(); } }вы, вероятно, хотите сделать обработку ошибок более надежной, хотя. Извините за шаблон, проверенные исключения не позволяют нам полностью функционировать здесь.
получается, что Коллекционеры.toMap() ненавидит значения null. Вот более императивная версия приведенного выше кода:
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); } }
можно использовать размышления база для этого
import org.reflections.ReflectionUtils.*; Set<Method> getters = ReflectionUtils.getAllMethods(someClass, ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));
// 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()); }
Весна предлагает простой метод BeanUtil для самоанализа бобов:
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property); Method getter = pd.getReadMethod();
этот код тестируется нормально.
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(); } }
вы должны поддерживать универсальный геттер в каждом Бобе, так что для вызова getAttribute1() вы должны быть в состоянии вызвать универсальный геттер get("Attribute1")
этот универсальный геттер, в свою очередь, вызовет правильный геттер
Object get(String attribute) { if("Attribute1".equals(attribute) { return getAttribute1(); } }этот подход предполагает, что вы поддерживаете этот отдельный список в каждом компоненте, но таким образом вы избегаете отражения, которое имеет проблемы с производительностью, поэтому, если вы пишете производственный код, который должен иметь хорошую производительность, вы можете использовать выше шаблон для всех ваших бобов.
Если это какой-то тестовый код или код утилиты, который не имеет высоких требований к производительности, то вам лучше использовать другие подходы, поскольку этот подход подвержен ошибкам, если вы не можете написать какую-то проверку времени компиляции, которая гарантирует, что эта общая функция getter работает для всех атрибутов.
Comments