2011-10-11 11 views
10

Obiekt Moja Domena zawiera kilka pól Joda-Time DateTime. Kiedy czytam wartości bazy danych za pomocą SimpleJdbcTemplate:Przesłanianie BeanPropertyRowMapper do obsługi JodaTime DateTime

Pacjenta = jdbc.queryForObject (SQL, nowe BeanPropertyRowMapper (Patient.class) ID_Pacjenta);

Po prostu nie udaje się zaskoczyć, nie zarejestrowano żadnych błędów. Domyślam się, że to z powodu timestamp parsowania do DateTime nie działa z Jdbc.

Jeśli jest to możliwe, aby dziedziczyć i zastąpić BeanPropertyRowMapper i instruować przekonwertować wszystkie java.sql.Timestamp i java.sql.Date do DateTime, byłoby super, a może zaoszczędzić dużo dodatkowego kodu.

Każda rada?

Odpowiedz

21

Prawidłowe rzeczą do zrobienia jest do podklasy BeanPropertyRowMapper, zastępują initBeanWrapper(BeanWrapper) i zarejestruj niestandardowy edytor właściwości:

public class JodaDateTimeEditor extends PropertyEditorSupport { 
    @Override 
    public void setAsText(final String text) throws IllegalArgumentException { 
     setValue(new DateTime(text)); // date time in ISO8601 format 
             // (yyyy-MM-ddTHH:mm:ss.SSSZZ) 
    } 
    @Override 
    public void setValue(final Object value) { 
     super.setValue(value == null || value instanceof DateTime ? value 
             : new DateTime(value)); 
    } 
    @Override 
    public DateTime getValue() { 
     return (DateTime) super.getValue(); 
    } 
    @Override 
    public String getAsText() { 
     return getValue().toString(); // date time in ISO8601 format 
             // (yyyy-MM-ddTHH:mm:ss.SSSZZ) 
    } 
} 
public class JodaTimeSavvyBeanPropertyRowMapper<T> 
        extends BeanPropertyRowMapper<T> { 
    @Override 
    protected void initBeanWrapper(BeanWrapper bw) { 
     bw.registerCustomEditor(DateTime.class, new JodaDateTimeEditor()); 
    } 
} 
+0

Dokładnie tego szukam. Jednak dla mnie to naprawdę nie działa. Wykonanie zatrzymuje się w momencie, w którym następuje odwzorowanie DateTime, ale nie zarejestrowano błędów: 'DEBUG: com.keype.hawk.system.jdbc.support.HawkBeanPropertyRowMapper [mapRow]: Odwzorowanie kolumny 'date_added' na właściwość 'dateAdded' typu class org. joda.time.DateTime' –

+0

W końcu udało się rozwiązać problem. Komenda setValue() jest wywoływana z obiektem TimeStamp jako parametrem, ale w rzeczywistości jest to JodaTime Per my logger: 'Un supported object 2011-10-12 00: 00: 00.0. Typ obiektu: java.sql.Timestamp. Expected DateTime' –

+0

@firdousamir ok, zmieniłem kod teraz. Wypróbuj tę wersję. –

2

Patrząc na BeanPropertyRowMapper realizacji, sposób ustawia pola to:

Object value = getColumnValue(rs, index, pd); 

if (logger.isDebugEnabled() && rowNumber == 0) { 
    logger.debug("Mapping column '" + column + "' to property '" + 
    pd.getName() + "' of type " + pd.getPropertyType()); 
} 
try { 
    bw.setPropertyValue(pd.getName(), value); 
} 

gdzie getColumnValue(rs, index, pd); delegaci do JdbcUtils.getResultSetValue

To pd pola w getColumnValue jest rzeczywista "p roperty d escriptor ", który jest używany (pd.getPropertyType()) w JdbcUtils jako typ pola do odwzorowania na.

Jeśli spojrzeć na kod JdbcUtils dla getResultSetValue metody, zobaczysz, że po prostu idzie z jednego if rachunku do innego, aby dopasować pd.getPropertyType() do wszystkich standardowych typów. Gdy nie znajdziesz, ponieważ DateTime nie jest „standard” typ, opiera się ona na rs.getObject():

} else { 
// Some unknown type desired -> rely on getObject. 

Następnie, jeśli ten obiekt jest data SQL konwertuje go do Timestamp i zwraca się ustawić do pola DateTime Twojej domeny => w przypadku niepowodzenia.

Stąd, nie wydaje się być prosta droga do wstrzyknąć Date/Timestamp do DateTime konwerter do BeanPropertyRowMapper. Byłoby więc czystsze (i bardziej wydajne), aby zaimplementować własną aplikację RowMapper.

Jeśli chcesz zobaczyć błąd mapowania w konsoli, ustaw poziom logowania na org.springframework.jdbc na "debugowanie" lub jeszcze lepiej "śledź", aby zobaczyć dokładnie, co się stanie.

Jedno można spróbować, które nie zostały przetestowane, to rozszerzyć BeanPropertyRowMapper i zastąpić właściwość DateTime typu w:

/** 
* Initialize the given BeanWrapper to be used for row mapping. 
* To be called for each row. 
* <p>The default implementation is empty. Can be overridden in subclasses. 
* @param bw the BeanWrapper to initialize 
*/ 
protected void initBeanWrapper(BeanWrapper bw) {} 
+0

Dzięki tolitius. To jest to co zrobiłem. Nie mogłem znaleźć drogi. Niestandardowy rząd jest taki. –

1

Odpowiedź @Sean Patrick Floyd jest idealna, dopóki nie masz wielu niestandardowych typów.

Tutaj uogólniona, konfigurowalne oparte na przedłużenie użytkowania:

public class CustomFieldTypeSupportBeanPropertyRowMapper<T> extends BeanPropertyRowMapper<T> { 
    private Map<Class<?>, Handler> customTypeMappers = new HashMap<Class<?>, Handler>(); 

    public CustomFieldTypeSupportBeanPropertyRowMapper() { 
    super(); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, boolean checkFullyPopulated) { 
    super(mappedClass, checkFullyPopulated); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass) { 
    super(mappedClass); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, Map<Class<?>, Handler> customTypeMappers) { 
    super(mappedClass); 
    this.customTypeMappers = customTypeMappers; 
    } 

    @Override 
    protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException { 
    final Class<?> current = pd.getPropertyType(); 
    if (customTypeMappers.containsKey(current)) { 
     return customTypeMappers.get(current).f(rs, index, pd); 
    } 
    return super.getColumnValue(rs, index, pd); 
    } 

    public void addTypeHandler(Class<?> class1, Handler handler2) { 
    customTypeMappers.put(class1, handler2); 
    } 

    public static interface Handler { 
    public Object f(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException; 
    } 
} 
Powiązane problemy