Mybatis的TypeReference泛型引用

mybatis中有许多精巧的代码,现分析其中一个TypeReference来学习一下。

其代码路径为:

org.apache.ibatis.type.TypeReference<T>

参考jar文件:mybatis-3.4.5.jar

完整代码为:

/**
 *    Copyright 2009-2016 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * References a generic type.
 *
 * @param <T> the referenced type
 * @since 3.1.0
 * @author Simone Tripodi
 */
public abstract class TypeReference<T> {

  private final Type rawType;

  protected TypeReference() {
    rawType = getSuperclassTypeParameter(getClass());
  }

  Type getSuperclassTypeParameter(Class<?> clazz) {
    Type genericSuperclass = clazz.getGenericSuperclass();
    if (genericSuperclass instanceof Class) {
      // try to climb up the hierarchy until meet something useful
      if (TypeReference.class != genericSuperclass) {
        return getSuperclassTypeParameter(clazz.getSuperclass());
      }

      throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
        + "Remove the extension or add a type parameter to it.");
    }

    Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
    // TODO remove this when Reflector is fixed to return Types
    if (rawType instanceof ParameterizedType) {
      rawType = ((ParameterizedType) rawType).getRawType();
    }

    return rawType;
  }

  public final Type getRawType() {
    return rawType;
  }

  @Override
  public String toString() {
    return rawType.toString();
  }

}

编写测试类:

import org.apache.ibatis.type.TypeReference;

public class TestTypeReference {
	
    public static void main(String[] args) {
		TypeReference<String> typeReference = new TypeReference<String>() {
		};
    	System.out.println(typeReference.getRawType());
	}
    
}

以上测试类输出结果为:class java.lang.String

    TypeReference在这里必须被实例化之后,才能够被读取到泛型的内容,他本身被定义为abstract抽象的,又因为他并没有抽象方法,所以在new的时候需要加空花括号,表示实例化一个抽象类的匿名实现类实例。

    其实,主体的逻辑就都在构造方法里了,rawType = getSuperclassTypeParameter(getClass()); 这一句代码完成了泛型的读取。

下面边调试边分析他的解析过程:

可以看到,当前类(也就是咱们的匿名TypeReference实现类)的名字是TypeREfrence$1,那么他的父类一定是TypeReference,这里面有一个递归处理:

也就是只要父类是TypeReference即可,至于是几层继承,没关系。但当最后也没找到TypeReference这个非Class类型的class时,就报错。

跟踪调试,genericSuperclass的值的getClass()结果是:

()sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl,其实这里得到的superClass就是TypeReference而已,而TypeReference被定义为泛型的,所以他的class对象具体类型是ParameterizedTypeImpl,他不是一个Class的instance,而是ParameterizedType接口的一个实例。

然后就调用 ParameterizedType#getActualTypeArguments()这个方法获取到泛型数组,即可读取到泛型结果了。

     这个类的应用场景,比如想要传递Map<String,Object>这样一个类型信息,我们无法Map<String,Object>.class的方式传递,此时我们可以通过 new TypeReference<Map<String,Object>(){}对象传递获取:

TypeReference<Map<String,Object>> typeReference = new TypeReference<Map<String,Object>>() {
		};
System.out.println(typeReference.getRawType());
Type genericSuperclass = typeReference.getClass().getGenericSuperclass();
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; // Map<String,Object>
System.out.println(((ParameterizedType)rawType).getActualTypeArguments()[0]); // String
System.out.println(((ParameterizedType)rawType).getActualTypeArguments()[1]); // Object

是不是挺好用的?

特别需要注意的是,test2这个例子中,直接typeReference.getRawType()返回的是interface java.util.Map,是不带泛型信息的。 

Mybatis中,可以使用通用mapper插件来实现通用增删改查操作。通用mapper插件提供了各种高效的工具,可以简化开发者的工作,提高代码质量和开发效率。 下面是使用通用mapper插件实现通用增删改查的示例代码: 1. 引入通用mapper插件的依赖: ```xml <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>4.1.5</version> </dependency> ``` 2. 创建实体类: ```java public class User { private Long id; private String name; // 省略getter和setter方法 } ``` 3. 创建Mapper接口: ```java @Mapper public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User> { } ``` 4. 在配置文件中配置通用mapper插件: ```xml <configuration> <!-- 其他配置 --> <plugins> <plugin interceptor="tk.mybatis.mapper.autoconfigure.MapperInterceptor"> <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/> </plugin> </plugins> </configuration> ``` 5. 使用通用mapper插件进行增删改查操作: ```java @Autowired private UserMapper userMapper; // 查询所有用户 List<User> userList = userMapper.selectAll(); // 根据主键查询用户 User user = userMapper.selectByPrimaryKey(1L); // 插入用户 User newUser = new User(); newUser.setName("张三"); userMapper.insert(newUser); // 更新用户 User updateUser = new User(); updateUser.setId(1L); updateUser.setName("李四"); userMapper.updateByPrimaryKey(updateUser); // 删除用户 userMapper.deleteByPrimaryKey(1L); ``` 通过以上步骤,我们可以使用通用mapper插件实现通用增删改查操作,避免了大量的SQL编写,提高了开发效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

brimsullowr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值