Используйте неявный TypeHandler на основе resultType для выбора в MyBatis

Я пытаюсь выбрать временную метку в MyBatis и возвращать ее как LocalDateTime (от joda-time).

Моя конфигурация отлично работает, если я попытаюсь вернуть результат как java.sql.Timestamp. Я доказал, что мой обработчик типа отлично работает: если я использую класс упаковки с LocalDateTime как только полем и resultMap в файле MapBaris, я получаю правильные результаты.

Однако, когда я пытаюсь указать org.joda.time.LocalDateTime как resultType для этого select, я всегда получаю null, как если бы обработчик типа игнорировался.

Насколько я понимаю, MyBatis использует типHandler по умолчанию, если у меня есть resultType="java.sql.Timestamp". Как следствие, я ожидал, что он будет использовать один из типов, которые я настроил при встрече resultType="org.joda.time.LocalDateTime".

Я что-то пропустил? Есть ли способ использовать мой типHandler, или я вынужден сделать класс-оболочку и resultMap? Это мое решение для отказа, но я хотел бы избежать его, если это возможно.

Любая помощь оценивается. Спасибо.

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeHandlers>
        <typeHandler javaType="org.joda.time.LocalDate" jdbcType="DATE" handler="...LocalDateTypeHandler"/>
        <typeHandler javaType="org.joda.time.LocalDateTime" jdbcType="TIMESTAMP" handler="...LocalDateTimeTypeHandler"/>
    </typeHandlers>
</configuration>

NotifMailDao.java

import org.joda.time.LocalDateTime;

public interface NotifMailDao {

    LocalDateTime getLastNotifTime(String userId);
}

NotifMailDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="lu.bgl.notif.mail.dao.NotifMailDao">

    <select id="getLastNotifTime" resultType="org.joda.time.LocalDateTime">
        SELECT current_timestamp
        AS last_time
        FROM DUAL
    </select>
</mapper>

Ответ 1

Чтобы использовать конфигурацию TypeHandler, MyBatis должен знать как тип Java результирующего объекта, так и тип SQL исходного столбца.

Здесь мы используем resultType в <select />, поэтому MyBatis знает тип Java, но он не может знать тип SQL, если мы его не установим. Единственный способ - использовать <resultMap />.

Решение

Вам нужно создать Bean с одним полем, содержащим объект, который вы хотите вернуть (назовем это поле time) и используйте <resultMap />:

<select id="getLastNotifTime" resultMap="notifMailResultMap">

<resultMap id="mapLastTime" type="MyWrapperBean">
    <result property="time" column="my_sql_timestamp" javaType="org.joda.time.LocalDateTime"
        jdbcType="TIMESTAMP" />
</resultMap>

Если вы хотите зарезервировать создание выделенного bean, вы также можете использовать атрибут type=hashmap на своем <resultMap />, как предлагается Shobit.

Вариант: установите свойство на LocalDateTime

A решение было предложено в группах Google, которое непосредственно устанавливает информацию о LocalDateTime.

Мое понимание этого (прокомментируйте, если я ошибаюсь) заключается в том, что он устанавливает свойство LocalDateTime. Я не буду ручаться за него, так как я не нашел соответствующее в API doc (и я его не тестировал), но не стесняйтесь использовать если вы сочтете это лучше.

<resultMap id="mapLastTime" type="org.joda.time.LocalDateTime">
    <result property="lastTime" column="my_sql_timestamp" javaType="org.joda.time.LocalDateTime"
        jdbcType="TIMESTAMP" />
</resultMap>

Почему он работает с java.sql.Timestamp

Timestamp - стандартный Java-тип для SQL с реализацией JDBC по умолчанию (ResultSet.getTimestamp(int/String)). Обработчик по умолчанию для MyBatis использует этот getter 1 и поэтому не нуждается в сопоставлении TypeHandler. Я ожидаю, что это произойдет каждый раз, когда вы используете один из обработчиков по умолчанию.


1: Это догадка. Требуется ссылка!

Этот ответ ожидает только замены чего-то лучшего. Пожалуйста, внесите свой вклад!