J'écris une classe Java qui a beaucoup de getters ... maintenant je veux obtenir toutes les méthodes getter et les appeler de temps en temps..Je sais qu'il existe des méthodes telles que getMethods () ou getMethod (nom de chaîne, Classe ... paramètreTypes), mais je veux juste obtenir le getter en effet ..., utilisez regex - tout le monde peut me le dire? Merci!
N'utilisez pas de regex, utilisez le 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());
}
Généralement, vous ne voulez pas de propriétés dans Object.class, vous utiliseriez donc la méthode avec deux paramètres:
Introspector.getBeanInfo(yourClass, stopClass)
// usually with Object.class as 2nd param
// the first class is inclusive, the second exclusive
BTW: il existe des cadres qui le font pour vous et vous présentent une vue de haut niveau. Par exemple. commons/beanutils a la méthode
Map<String, String> properties = BeanUtils.describe(yourObject);
( docs here ) qui fait justement cela: trouver et exécuter tous les getters et stocker le résultat dans une carte. Malheureusement, BeanUtils.describe()
convertit toutes les valeurs de propriété en chaînes avant de renvoyer. WTF. Merci @danw
Mise à jour:
Voici une méthode Java 8) qui renvoie un Map<String, Object>
En fonction des propriétés du bean d'un objet.
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();
}
}
Cependant, vous voulez probablement rendre la gestion des erreurs plus robuste. Désolé, les exceptions vérifiées nous empêchent de fonctionner pleinement ici.
Il s'avère que Collectors.toMap () déteste les valeurs nulles. Voici une version plus impérative du code ci-dessus:
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();
}
}
Voici la même fonctionnalité d'une manière plus concise, en utilisant 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();
}
}
Et voici une version de goyave:
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);
}
}
Vous pouvez utiliser le cadre Reflections pour cela
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());
}
Spring offre un moyen facile méthode BeanUtil pour l'introspection de Bean:
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property);
Method getter = pd.getReadMethod();
Ce code est testé 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();
}
}