Using Custom Type Handlers in MyBatis for Java Types

Answered using GPT-4o-mini by Java Q&A Hub

Question:

Can you explain how to use a custom type handler with MyBatis? How does it work?

Answer:

Certainly! In MyBatis, a custom type handler allows you to define how to map a specific Java type to a database type and vice versa. This is particularly useful when you have a Java type that doesn't have a direct mapping to a SQL type or when you want to customize the way data is read from or written to the database.

How to Use a Custom Type Handler in MyBatis

Here’s a step-by-step guide on how to create and use a custom type handler in MyBatis:

Step 1: Create a Custom Type Handler

You need to create a class that extends BaseTypeHandler<T>, where T is the Java type you want to handle. You will need to implement the following methods:

  • setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType): This method is used to set the parameter in the prepared statement.
  • getNullableResult(ResultSet rs, String columnName): This method retrieves the result from the result set using the column name.
  • getNullableResult(ResultSet rs, int columnIndex): This method retrieves the result from the result set using the column index.
  • getNullableResult(CallableStatement cs, int columnIndex): This method retrieves the result from the callable statement.

Here’s an example of a custom type handler for a LocalDate type:

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, LocalDate parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.format(formatter));
    }

    @Override
    public LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String date = rs.getString(columnName);
        return date != null ? LocalDate.parse(date, formatter) : null;
    }

    @Override
    public LocalDate getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String date = rs.getString(columnIndex);
        return date != null ? LocalDate.parse(date, formatter) : null;
    }

    @Override
    public LocalDate getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String date = cs.getString(columnIndex);
        return date != null ? LocalDate.parse(date, formatter) : null;
    }
}

Step 2: Register the Custom Type Handler

You can register the custom type handler in your MyBatis configuration file (XML) or using annotations.

XML Configuration:

<typeHandlers>
    <typeHandler handler="com.example.LocalDateTypeHandler" javaType="java.time.LocalDate"/>
</typeHandlers>

Annotation Configuration:

If you are using annotations, you can specify the type handler directly in your mapper interface:

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

public interface MyMapper {
    @Select("SELECT * FROM my_table WHERE my_date = #{myDate, typeHandler=com.example.LocalDateTypeHandler}")
    MyEntity selectByDate(@Param("myDate") LocalDate myDate);
}

Step 3: Use the Custom Type Handler

Now, you can use your custom type handler in your mapper methods. When you pass a LocalDate to a method that uses this type handler, MyBatis will automatically use your custom logic to convert it to a string for the database and back to a LocalDate when retrieving it.

How It Works

  1. Parameter Setting: When you call a method that uses the custom type handler, MyBatis invokes the setNonNullParameter method to convert the LocalDate to a string format before sending it to the database.

  2. Result Retrieval: When MyBatis retrieves data from the database, it calls the appropriate getNullableResult method to convert the string back to a LocalDate.

  3. Flexibility: This approach allows you to handle complex types, perform custom conversions, and manage null values effectively.

Conclusion

Custom type handlers in MyBatis provide a powerful way to manage data types that require special handling. By implementing the BaseTypeHandler class, you can define how your Java types interact with the database, ensuring that your application can handle data in a way that meets your specific requirements.