12

私のドメイン オブジェクトには、いくつかの Joda-TimeDateTimeフィールドがあります。SimpleJdbcTemplate を使用してデータベースの値を読み取る場合:

患者の患者 = jdbc.queryForObject(sql, new BeanPropertyRowMapper(Patient.class), patientId);

失敗するだけで、驚くべきことに、エラーはログに記録されませんでした。timestamp解析DateTimeがJdbcで機能していないためだと思います。

継承してオーバーライドし、 allとをBeanPropertyRowMapperに変換するように指示することができれば、それは素晴らしいことであり、余分なコードを大幅に節約できます。java.sql.Timestampjava.sql.DateDateTime

何かアドバイス?

4

3 に答える 3

22

正しいことは、カスタム プロパティ エディタをサブクラス化BeanPropertyRowMapperし、オーバーライドして登録することです。initBeanWrapper(BeanWrapper)

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());
    }
}
于 2011-10-12T14:59:18.827 に答える
2

実装を見るとBeanPropertyRowMapper、フィールドを設定する方法は次のとおりです。

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);
}

JdbcUtils.getResultSetValuegetColumnValue(rs, index, pd);デリゲートする場所

のそのpdフィールドgetColumnValueは実際の「プロパティ記述」であり、マップ先のフィールドのタイプとして( pd.getPropertyType()) で使用されます。JdbcUtils

JdbcUtilsメソッドのコードを見ると、すべての標準型に一致するように、あるステートメントから別のステートメントにgetResultSetValue単純に移行することがわかります。見つからない場合は、「標準」タイプではないため、以下に依存します。ifpd.getPropertyType()DateTimers.getObject()

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

次に、このオブジェクトが SQL Date の場合、それを に変換し、ドメインのフィールドにTimestamp設定されるように戻ります => 失敗する場所。DateTime

Dateしたがって、 / TimestamptoDateTimeコンバーターをに挿入する簡単な方法はないようですBeanPropertyRowMapper。そのため、独自の RowMapper を実装する方がクリーン (かつパフォーマンスが高い) でしょう。

コンソールでマッピング エラーを確認したい場合は、ロギング レベルorg.springframework.jdbcを「デバッグ」または「トレース」に設定して、何が起こっているかを正確に確認してください。

私がテストしていないことの 1 つは、次のタイプBeanPropertyRowMapperのプロパティを拡張してオーバーライドすることです。DateTime

/**
 * 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) {}
于 2011-10-12T02:43:49.553 に答える
1

@Sean Patrick Floyd の答えは、多くのカスタム タイプがなくなるまで完璧です。

ここでは、使用拡張に基づいて一般化され、構成可能です。

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;
  }
}
于 2014-07-23T13:19:36.840 に答える