Я пишу класс java, который имеет много геттеров. Теперь я хочу получить все методы getter и вызывать их когда-нибудь. Я знаю, что существуют такие методы, как getMethods() или getMethod (String name, Class... parameterTypes), но я просто хочу получить getter действительно..., используйте regex? кто-нибудь может сказать мне? Спасибо!
Java Reflection: как я могу получить все методы getter класса java и вызывать их
Ответ 1
Не используйте регулярное выражение, используйте 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), который делает именно это: найти и выполнить все геттеры и сохранить результат на карте. К сожалению, BeanUtils.describe()
преобразует все значения свойств в строки перед возвратом. WTF. Спасибо @danw
Update:
Здесь используется метод 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();
}
}
Вероятно, вы хотите сделать обработку ошибок более надежной. Извините за шаблон, проверенные исключения не позволяют нам полностью функционировать здесь.
Оказывается, что 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();
}
}
И здесь версия 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);
}
}
Ответ 2
Вы можете использовать Reflections для этого
import org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));
Ответ 3
// 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());
}
Ответ 4
Spring предлагает простой метод BeanUtil для Bean интроспекция:
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property);
Method getter = pd.getReadMethod();
Ответ 5
Вы должны поддерживать общий getter в каждом bean, чтобы вызывать getAttribute1(), вы должны иметь возможность вызвать общий getter get ( "Attribute1" )
Этот общий геттер в свою очередь вызовет правильный getter
Object get(String attribute)
{
if("Attribute1".equals(attribute)
{
return getAttribute1();
}
}
Этот подход предполагает, что вы поддерживаете этот отдельный список в каждом bean, но таким образом избегаете отражения, которое имеет проблемы с производительностью, поэтому, если вы пишете производственный код, который должен иметь хорошую производительность, вы можете использовать приведенный выше шаблон для всех ваших beans.
Если это какой-то тестовый код или код полезности, который не имеет требований к высокой производительности, вам лучше использовать другие подходы, поскольку этот подход подвержен ошибкам, если вы не можете написать какой-то счетчик времени компиляции, который гарантирует, что эта общая функция getter работает для всех атрибутов.