2010-07-09 14 views
8

Mam POJO i (obecnie jeszcze nie-zbudowany) klasy, która zwróci listę. Chciałbym automatycznie wygenerować kod niezbędny do uzyskania dostępu do POJO jako mapy. Czy jest to dobry pomysł, czy można to zrobić automatycznie i czy muszę to robić ręcznie dla każdego POJO, które chcę traktować w ten sposób?Generuj mapę <String, String> z POJO

Dzięki Andy

Odpowiedz

16

Można użyć Commons BeanUtilsBeanMap do tego.

Map map = new BeanMap(someBean); 

Aktualizacja: ponieważ to nie jest opcja ze względu na pewne pozorne problemy z zależnościami biblioteki w Androidzie, oto prosty przykład kickoff jak można zrobić to z niewielką pomocą 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; 
} 

Jeśli dostępne były interfejsy API java.beans, można po prostu wykonać:

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; 
} 
+0

Holy crap! To wygląda na super przydatne! Czy wiesz coś na temat jego wpływu na wydajność? –

+1

Odbicie zawsze ma wpływ na wydajność. Nic przeciwko niemu. Ale możesz ufać, że faceci BeanUtils zoptymalizowali go tak bardzo, jak to tylko możliwe. To dość popularna biblioteka. – BalusC

+0

Cool. Czy muszę implementować dowolny interfejs w moich obiektach POJO lub czy używam get * naming wystarczająco (używam niezmiennych POJOs w/prywatnych konstruktorów utworzonych za pomocą Buildera)? –

1

Oto moja własna implementacja bez żadnych zależności. Zamiast tworzyć kopię stanu obiektu, implementuje on żywą mapę nad pojo. Android doesn't support java.beans, ale możesz zamiast tego użyć 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); 
     } 
    } 
} 
Powiązane problemy