私はPOJOと、そのリストを返す(現在はまだ構築されていない)クラスを持っています。POJO に Map としてアクセスするために必要なコードを自動的に生成したいと考えています。これは良い考えですか?自動的に行うことは可能ですか?この方法で処理したいすべての POJO に対して手動でこれを行う必要がありますか?
ありがとう、アンディ
私はPOJOと、そのリストを返す(現在はまだ構築されていない)クラスを持っています。POJO に Map としてアクセスするために必要なコードを自動的に生成したいと考えています。これは良い考えですか?自動的に行うことは可能ですか?この方法で処理したいすべての POJO に対して手動でこれを行う必要がありますか?
ありがとう、アンディ
これにはCommons BeanUtils を使用できますBeanMap
。
Map map = new BeanMap(someBean);
更新: Android の明らかなライブラリ依存関係の問題により、これはオプションではないため、Reflection APIをほとんど使用せずにそれを行う方法の基本的なキックオフの例を次に示します。
public static Map<String, Object> mapProperties(Object bean) throws Exception {
Map<String, Object> properties = new HashMap<>();
for (Method method : bean.getClass().getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& method.getReturnType() != void.class
&& method.getName().matches("^(get|is).+")
) {
String name = method.getName().replaceAll("^(get|is)", "");
name = Character.toLowerCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
Object value = method.invoke(bean);
properties.put(name, value);
}
}
return properties;
}
API が利用可能な場合java.beans
は、次のようにすることができます。
public static Map<String, Object> mapProperties(Object bean) throws Exception {
Map<String, Object> properties = new HashMap<>();
for (PropertyDescriptor property : Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors()) {
String name = property.getName();
Object value = property.getReadMethod().invoke(bean);
properties.put(name, value);
}
return properties;
}
これは、依存関係のない私自身の実装です。オブジェクトの状態のコピーを作成するのではなく、pojo にライブ Map を実装します。Androidはjava.beans をサポートしていませんが、代わりにopenbeansを使用できます。
import java.beans.*; // Or, import com.googlecode.openbeans.*
import java.util.*;
public class BeanMap extends AbstractMap<String, Object> {
private static final Object[] NO_ARGS = new Object[] {};
private HashMap<String, PropertyDescriptor> properties;
private Object bean;
public BeanMap(Object bean) throws IntrospectionException {
this.bean = bean;
properties = new HashMap<String, PropertyDescriptor>();
BeanInfo info = Introspector.getBeanInfo(bean.getClass());
for(PropertyDescriptor property : info.getPropertyDescriptors()) {
properties.put(property.getName(), property);
}
}
@Override public Object get(Object key) {
PropertyDescriptor property = properties.get(key);
if(property == null)
return null;
try {
return property.getReadMethod().invoke(bean, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override public Object put(String key, Object value) {
PropertyDescriptor property = properties.get(key);
try {
return property.getWriteMethod().invoke(bean, new Object[] {value});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override public Set<Map.Entry<String, Object>> entrySet() {
HashSet<Map.Entry<String, Object>> result = new HashSet<Map.Entry<String, Object>>(properties.size() * 2);
for(PropertyDescriptor property : properties.values()) {
String key = property.getName();
Object value;
try {
value = property.getReadMethod().invoke(bean, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
result.add(new PropertyEntry(key, value));
}
return Collections.unmodifiableSet(result);
}
@Override public int size() { return properties.size(); }
@Override public boolean containsKey(Object key) {
return properties.containsKey(key);
}
class PropertyEntry extends AbstractMap.SimpleEntry<String, Object> {
PropertyEntry(String key, Object value) {
super(key, value);
}
@Override public Object setValue(Object value) {
super.setValue(value);
return BeanMap.this.put(getKey(), value);
}
}
}