13、类型转换(TypeHandler)介绍

Mybatis中的TypeHandler是什么

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。Mybatis默认为我们实现了许多TypeHandler, 当我们没有配置指定TypeHandler时,Mybatis会根据参数或者返回结果的不同,默认为我们选择合适的TypeHandler处理。

如果你使用JSR-310(Date和Time API),你可以使用mybatis-typehandlers-jsr310

配置TypeHandler

 <typeHandlers>
   
        
        
        <typeHandler handler=""/>

        
        <typeHandler javaType="" handler=""/>

        
        <typeHandler jdbcType="" handler=""/>

        
        <typeHandler javaType="" jdbcType="" handler=""/>
 typeHandlers>

mybatis实现的类型转换

类型处理器 Java 类型 JDBC 类型
BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN
ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Short, short 数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.Integer, int 数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandler java.lang.Float, float 数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Double, double 数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHAR, VARCHAR
ClobReaderTypeHandler java.io.Reader -
ClobTypeHandler java.lang.String CLOB, LONGVARCHAR
NStringTypeHandler java.lang.String NVARCHAR, NCHAR
NClobTypeHandler java.lang.String NCLOB
BlobInputStreamTypeHandler java.io.InputStream -
ByteArrayTypeHandler byte[] 数据库兼容的字节流类型
BlobTypeHandler byte[] BLOB, LONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
DateOnlyTypeHandler java.util.Date DATE
TimeOnlyTypeHandler java.util.Date TIME
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
SqlDateTypeHandler java.sql.Date DATE
SqlTimeTypeHandler java.sql.Time TIME
ObjectTypeHandler Any OTHER 或未指定类型
EnumTypeHandler Enumeration Type VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。

xml配置源码

private void typeHandlerElement(XNode parent) throws Exception {
       if (parent != null) {
             for (XNode child : parent.getChildren()) {
               //子节点为package时,获取其name属性的值,然后自动扫描package下的自定义typeHandler
               if ("package".equals(child.getName())) {
                 String typeHandlerPackage = child.getStringAttribute("name");
                 typeHandlerRegistry.register(typeHandlerPackage);
               } else {
                 //子节点为typeHandler时, 可以指定javaType属性, 也可以指定jdbcType, 也可两者都指定
                 //javaType 是指定java类型
                 //jdbcType 是指定jdbc类型(数据库类型: 如varchar)
                 String javaTypeName = child.getStringAttribute("javaType");
                 String jdbcTypeName = child.getStringAttribute("jdbcType");
                 //handler就是我们配置的typeHandler
                 String handlerTypeName = child.getStringAttribute("handler");
                 //resolveClass方法就是我们上篇文章所讲的TypeAliasRegistry里面处理别名的方法
                 Class javaTypeClass = resolveClass(javaTypeName);
                 //JdbcType是一个枚举类型,resolveJdbcType方法是在获取枚举类型的值
                 JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
                 Class typeHandlerClass = resolveClass(handlerTypeName);
                 //注册typeHandler, typeHandler通过TypeHandlerRegistry这个类管理
                 if (javaTypeClass != null) {
                   if (jdbcType == null) {
                     typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
                   } else {
                     typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
                   }
                 } else {
                   typeHandlerRegistry.register(typeHandlerClass);
                 }
               }
             }
           }
    }

TypeHandler的管理注册类


package org.apache.ibatis.type;

import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.Resources;

import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public final class TypeHandlerRegistry {
    private static final Map> NULL_TYPE_HANDLER_MAP = new HashMap>();

    //保存Mybatis内部提供的枚举JdbcType类型和对应的TypeHandler
    private final Map> JDBC_TYPE_HANDLER_MAP = new EnumMap>(JdbcType.class);

    //javaType的Class类型(Type是Class的接口),value是一个Map集合(比如String,可能对应数据库的clob、char、varchar等,所以是一对多关系)
    private final Map>> TYPE_HANDLER_MAP = new ConcurrentHashMap>>();

    //处理Object类型(运行时,会尝试进行向下类型转换找到合适的TypeHandler,如果依然失败,最后选择ObjectTypeHandler)
    private final TypeHandler UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);

    //所有的TypeHandler. Key:TypeHandler的Class类型,value:TypeHandler实例(都是singleton)
    private final Map, TypeHandler> ALL_TYPE_HANDLERS_MAP = new HashMap, TypeHandler>();


    // mybatis也默认给我们注册了不少的typeHandler
    public TypeHandlerRegistry() {
        register(Boolean.class, new BooleanTypeHandler());
        register(boolean.class, new BooleanTypeHandler());
        register(JdbcType.BOOLEAN, new BooleanTypeHandler());
        register(JdbcType.BIT, new BooleanTypeHandler());

        register(Byte.class, new ByteTypeHandler());
        register(byte.class, new ByteTypeHandler());
        register(JdbcType.TINYINT, new ByteTypeHandler());

        register(Short.class, new ShortTypeHandler());
        register(short.class, new ShortTypeHandler());
        register(JdbcType.SMALLINT, new ShortTypeHandler());

        register(Integer.class, new IntegerTypeHandler());
        register(int.class, new IntegerTypeHandler());
        register(JdbcType.INTEGER, new IntegerTypeHandler());

        register(Long.class, new LongTypeHandler());
        register(long.class, new LongTypeHandler());

        register(Float.class, new FloatTypeHandler());
        register(float.class, new FloatTypeHandler());
        register(JdbcType.FLOAT, new FloatTypeHandler());

        register(Double.class, new DoubleTypeHandler());
        register(double.class, new DoubleTypeHandler());
        register(JdbcType.DOUBLE, new DoubleTypeHandler());

        register(Reader.class, new ClobReaderTypeHandler());
        register(String.class, new StringTypeHandler());
        register(String.class, JdbcType.CHAR, new StringTypeHandler());
        register(String.class, JdbcType.CLOB, new ClobTypeHandler());
        register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
        register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
        register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
        register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
        register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
        register(JdbcType.CHAR, new StringTypeHandler());
        register(JdbcType.VARCHAR, new StringTypeHandler());
        register(JdbcType.CLOB, new ClobTypeHandler());
        register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
        register(JdbcType.NVARCHAR, new NStringTypeHandler());
        register(JdbcType.NCHAR, new NStringTypeHandler());
        register(JdbcType.NCLOB, new NClobTypeHandler());

        register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
        register(JdbcType.ARRAY, new ArrayTypeHandler());

        register(BigInteger.class, new BigIntegerTypeHandler());
        register(JdbcType.BIGINT, new LongTypeHandler());

        register(BigDecimal.class, new BigDecimalTypeHandler());
        register(JdbcType.REAL, new BigDecimalTypeHandler());
        register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
        register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

        register(InputStream.class, new BlobInputStreamTypeHandler());
        register(Byte[].class, new ByteObjectArrayTypeHandler());
        register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
        register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
        register(byte[].class, new ByteArrayTypeHandler());
        register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
        register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
        register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
        register(JdbcType.BLOB, new BlobTypeHandler());

        register(Object.class, UNKNOWN_TYPE_HANDLER);
        register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
        register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);

        register(Date.class, new DateTypeHandler());
        register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
        register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
        register(JdbcType.TIMESTAMP, new DateTypeHandler());
        register(JdbcType.DATE, new DateOnlyTypeHandler());
        register(JdbcType.TIME, new TimeOnlyTypeHandler());

        register(java.sql.Date.class, new SqlDateTypeHandler());
        register(java.sql.Time.class, new SqlTimeTypeHandler());
        register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

        // mybatis-typehandlers-jsr310
        try {
            // since 1.0.0
            register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler");
            register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler");
            register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler");
            register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler");
            register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler");
            register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler");
            register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler");
            // since 1.0.1
            register("java.time.Month", "org.apache.ibatis.type.MonthTypeHandler");
            register("java.time.Year", "org.apache.ibatis.type.YearTypeHandler");
            // since 1.0.2
            register("java.time.YearMonth", "org.apache.ibatis.type.YearMonthTypeHandler");
            register("java.time.chrono.JapaneseDate", "org.apache.ibatis.type.JapaneseDateTypeHandler");

        } catch (ClassNotFoundException e) {
            // no JSR-310 handlers
        }

        // issue #273
        register(Character.class, new CharacterTypeHandler());
        register(char.class, new CharacterTypeHandler());
    }

    public boolean hasTypeHandler(Class javaType) {
        return hasTypeHandler(javaType, null);
    }

    public boolean hasTypeHandler(TypeReference javaTypeReference) {
        return hasTypeHandler(javaTypeReference, null);
    }

    public boolean hasTypeHandler(Class javaType, JdbcType jdbcType) {
        return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;
    }

    public boolean hasTypeHandler(TypeReference javaTypeReference, JdbcType jdbcType) {
        return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null;
    }

    public TypeHandler getMappingTypeHandler(Class> handlerType) {
        return ALL_TYPE_HANDLERS_MAP.get(handlerType);
    }

    public  TypeHandler getTypeHandler(Class type) {
        return getTypeHandler((Type) type, null);
    }

    public  TypeHandler getTypeHandler(TypeReference javaTypeReference) {
        return getTypeHandler(javaTypeReference, null);
    }

    public TypeHandler getTypeHandler(JdbcType jdbcType) {
        return JDBC_TYPE_HANDLER_MAP.get(jdbcType);
    }

    public  TypeHandler getTypeHandler(Class type, JdbcType jdbcType) {
        return getTypeHandler((Type) type, jdbcType);
    }

    public  TypeHandler getTypeHandler(TypeReference javaTypeReference, JdbcType jdbcType) {
        return getTypeHandler(javaTypeReference.getRawType(), jdbcType);
    }
    /**
     * 配置了typeHandlerhe和javaType
     */
    @SuppressWarnings("unchecked")
    private  TypeHandler getTypeHandler(Type type, JdbcType jdbcType) {
        Map> jdbcHandlerMap = getJdbcHandlerMap(type);
        TypeHandler handler = null;
        if (jdbcHandlerMap != null) {
            handler = jdbcHandlerMap.get(jdbcType);
            if (handler == null) {
                handler = jdbcHandlerMap.get(null);
            }
            if (handler == null) {
                // #591
                handler = pickSoleHandler(jdbcHandlerMap);
            }
        }
        // type drives generics here
        return (TypeHandler) handler;
    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    private Map> getJdbcHandlerMap(Type type) {
        Map> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
        if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) {
            return null;
        }
        if (jdbcHandlerMap == null && type instanceof Class) {
            Class clazz = (Class) type;
            if (clazz.isEnum()) {
                jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(clazz);
                if (jdbcHandlerMap == null) {
                    register(clazz, new EnumTypeHandler(clazz));
                    return TYPE_HANDLER_MAP.get(clazz);
                }
            } else {
                jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);
            }
        }
        TYPE_HANDLER_MAP.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);
        return jdbcHandlerMap;
    }

    private Map> getJdbcHandlerMapForEnumInterfaces(Class clazz) {
        for (Class iface : clazz.getInterfaces()) {
            Map> jdbcHandlerMap = TYPE_HANDLER_MAP.get(iface);
            if (jdbcHandlerMap == null) {
                jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(iface);
            }
            if (jdbcHandlerMap != null) {
                return jdbcHandlerMap;
            }
        }
        return null;
    }

    private Map> getJdbcHandlerMapForSuperclass(Class clazz) {
        Class superclass = clazz.getSuperclass();
        if (superclass == null || Object.class.equals(superclass)) {
            return null;
        }
        Map> jdbcHandlerMap = TYPE_HANDLER_MAP.get(superclass);
        if (jdbcHandlerMap != null) {
            return jdbcHandlerMap;
        } else {
            return getJdbcHandlerMapForSuperclass(superclass);
        }
    }

    private TypeHandler pickSoleHandler(Map> jdbcHandlerMap) {
        TypeHandler soleHandler = null;
        for (TypeHandler handler : jdbcHandlerMap.values()) {
            if (soleHandler == null) {
                soleHandler = handler;
            } else if (!handler.getClass().equals(soleHandler.getClass())) {
                // More than one type handlers registered.
                return null;
            }
        }
        return soleHandler;
    }

    public TypeHandler getUnknownTypeHandler() {
        return UNKNOWN_TYPE_HANDLER;
    }

    public void register(JdbcType jdbcType, TypeHandler handler) {
        JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
    }

    //
    // REGISTER INSTANCE
    //

    // Only handler

    /**
     * 只配置了typeHandler
     */
    @SuppressWarnings("unchecked")
    public  void register(TypeHandler typeHandler) {
        //在自定义typeHandler的时候,可以加上注解MappedTypes 去指定关联的javaType
        //因此,此处需要扫描MappedTypes注解
        boolean mappedTypeFound = false;
        MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);
        if (mappedTypes != null) {
            for (Class handledType : mappedTypes.value()) {
                register(handledType, typeHandler);
                mappedTypeFound = true;
            }
        }
        // @since 3.1.0 - try to auto-discover the mapped type
        if (!mappedTypeFound && typeHandler instanceof TypeReference) {
            try {
                TypeReference typeReference = (TypeReference) typeHandler;
                register(typeReference.getRawType(), typeHandler);
                mappedTypeFound = true;
            } catch (Throwable t) {
                // maybe users define the TypeReference with a different type and are not assignable, so just ignore it
            }
        }
        if (!mappedTypeFound) {
            register((Class) null, typeHandler);
        }
    }

    // java type + handler

    public  void register(Class javaType, TypeHandler typeHandler) {
        register((Type) javaType, typeHandler);
    }

    /**
     * 只配置了typeHandle和JavaType
     * @param javaType
     * @param typeHandler
     * @param 
     */
    private  void register(Type javaType, TypeHandler typeHandler) {
        MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
        if (mappedJdbcTypes != null) {
            for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
                register(javaType, handledJdbcType, typeHandler);
            }
            if (mappedJdbcTypes.includeNullJdbcType()) {
                register(javaType, null, typeHandler);
            }
        } else {
            register(javaType, null, typeHandler);
        }
    }

    public  void register(TypeReference javaTypeReference, TypeHandler handler) {
        register(javaTypeReference.getRawType(), handler);
    }

    // java type + jdbc type + handler

    public  void register(Class type, JdbcType jdbcType, TypeHandler handler) {
        register((Type) type, jdbcType, handler);
    }

    /**
     * 都配置了
     * @param javaType
     * @param jdbcType
     * @param handler
     */
    private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) {
        if (javaType != null) {
            Map> map = TYPE_HANDLER_MAP.get(javaType);
            if (map == null) {
                map = new HashMap>();
                TYPE_HANDLER_MAP.put(javaType, map);
            }
            map.put(jdbcType, handler);
        }
        ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
    }

    //
    // REGISTER CLASS
    //

    // Only handler type

    public void register(Class typeHandlerClass) {
        boolean mappedTypeFound = false;
        MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
        if (mappedTypes != null) {
            for (Class javaTypeClass : mappedTypes.value()) {
                register(javaTypeClass, typeHandlerClass);
                mappedTypeFound = true;
            }
        }
        if (!mappedTypeFound) {
            register(getInstance(null, typeHandlerClass));
        }
    }

    // java type + handler type

    public void register(String javaTypeClassName, String typeHandlerClassName) throws ClassNotFoundException {
        register(Resources.classForName(javaTypeClassName), Resources.classForName(typeHandlerClassName));
    }

    public void register(Class javaTypeClass, Class typeHandlerClass) {
        register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
    }

    // java type + jdbc type + handler type

    public void register(Class javaTypeClass, JdbcType jdbcType, Class typeHandlerClass) {
        register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
    }

    // Construct a handler (used also from Builders)

    @SuppressWarnings("unchecked")
    public  TypeHandler getInstance(Class javaTypeClass, Class typeHandlerClass) {
        if (javaTypeClass != null) {
            try {
                Constructor c = typeHandlerClass.getConstructor(Class.class);
                return (TypeHandler) c.newInstance(javaTypeClass);
            } catch (NoSuchMethodException ignored) {
                // ignored
            } catch (Exception e) {
                throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
            }
        }
        try {
            Constructor c = typeHandlerClass.getConstructor();
            return (TypeHandler) c.newInstance();
        } catch (Exception e) {
            throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
        }
    }


    /**
     * 根据包扫描
     * @param packageName
     */
    public void register(String packageName) {
        ResolverUtil> resolverUtil = new ResolverUtil>();
        resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
        Set>> handlerSet = resolverUtil.getClasses();
        for (Class type : handlerSet) {
            //Ignore inner classes and interfaces (including package-info.java) and abstract classes
            if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
                register(type);
            }
        }
    }


    public Collection> getTypeHandlers() {
        return Collections.unmodifiableCollection(ALL_TYPE_HANDLERS_MAP.values());
    }

}

管理器中,真正实现功能的方法有3个
根据包扫描的

  private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) {
        if (javaType != null) {
            Map> map = TYPE_HANDLER_MAP.get(javaType);
            if (map == null) {
                map = new HashMap>();
                TYPE_HANDLER_MAP.put(javaType, map);
            }
            map.put(jdbcType, handler);
        }
        ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
    }
    public void register(Class typeHandlerClass) {
        boolean mappedTypeFound = false;
        MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
        if (mappedTypes != null) {
            for (Class javaTypeClass : mappedTypes.value()) {
                register(javaTypeClass, typeHandlerClass);
                mappedTypeFound = true;
            }
        }
        if (!mappedTypeFound) {
            register(getInstance(null, typeHandlerClass));
        }
    }
  /**
     * 都配置了
     * @param javaType
     * @param jdbcType
     * @param handler
     */
    private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) {
        if (javaType != null) {
            Map> map = TYPE_HANDLER_MAP.get(javaType);
            if (map == null) {
                map = new HashMap>();
                TYPE_HANDLER_MAP.put(javaType, map);
            }
            map.put(jdbcType, handler);
        }
        ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
    }

你可能感兴趣的:(Mybatis源码解析)