it-swarm-pt.tech

Java Reflexão: Como posso obter todos os métodos getter de uma classe Java e invocá-los

Eu escrevo uma classe Java que tem muitos getters .. agora eu quero obter todos os métodos getter e invocá-los em algum momento .. Eu sei que existem métodos como getMethods () ou getMethod (String name, Class .. . parameterTypes), mas eu só quero obter o getter de fato ..., use regex? alguém pode me dizer? Obrigado!

65
user996505

Não use regex, use o 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());
}

Normalmente você não deseja propriedades do Object.class, portanto, usaria o método com dois parâmetros:

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

BTW: existem estruturas que fazem isso por você e apresentam uma visão de alto nível. Por exemplo. commons/beanutils tem o método

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

( docs aqui ) que faz exatamente isso: encontre e execute todos os getters e armazene o resultado em um mapa. Infelizmente, BeanUtils.describe() converte todos os valores da propriedade em Strings antes de retornar. WTF. Obrigado @danw


Atualização:

Aqui está um método Java 8 que retorna um Map<String, Object> com base nas propriedades do bean de um objeto.

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

Você provavelmente deseja tornar o tratamento de erros mais robusto. Desculpe pelo clichê, as exceções marcadas nos impedem de ficar totalmente funcionais aqui.


Acontece que Collectors.toMap () odeia valores nulos. Aqui está uma versão mais imperativa do código acima:

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

Aqui está a mesma funcionalidade de uma maneira mais concisa, usando 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();

    }
}

E aqui está uma versão do Guava:

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);
    }
}
144
Sean Patrick Floyd

Você pode usar a estrutura Reflexões para este

import org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));
18
Naveedur Rahman
 // 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());
    }
9
dku.rajkumar

Spring oferece um fácil método BeanUtil para a introspecção do Bean:

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

Este código foi testado 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();
        }
    }
1
Sayan Mukherjee