每天进步一点点 - MyBatis使用xml编写mapper文件时,内部类的问题

453 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

序言

重构的时候,有一个业务场景,只需要给返回个Map对象就行,可是写完之后,发现Swagger里面没有对应的字段说明,不太友好。

但是这个结果集就这个地方用,所以就搞了一个内部类扔到对应的返回结果集中。

然后呢,在mapper里面标记返回值的时候,一直有问题,上网查了一番之后,才知道写错了,就记录一下吧。

第一个问题说明

在mapper里面声明返回值的时候,使用平常那种包名点的方式指定的。

<select id="getMaterialInfoByCodeOrName"
            resultType="com.mengli.InfoDTO.TestInfo">
        SELECT * 
        FROM
        material material
</select>

结果修改完之后,启动项目,报错:

Caused by: java.lang.ClassNotFoundException: Cannot find class: com.mengli.InfoDTO.TestInfo
	at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:200)
	at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89)
	at org.apache.ibatis.io.Resources.classForName(Resources.java:261)
	at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:116)
	... 83 common frames omitted

第一个问题原因

在MyBatis的mapper文件中使用内部类的方式为:类$内部类,而不是平常使用的那样使用.来获取。

所以上面的xml需要改成:

<select id="getMaterialInfoByCodeOrName"
            resultType="com.mengli.InfoDTO$TestInfo">
        SELECT * 
        FROM
        material material
</select>

第二个问题说明

在改完之后呢,执行查询的时候,还是报错,只不过这个错不是上面那个错了,而是:java.lang.NoSuchMethodException:

具体的异常信息就不贴了,大概的意思是这个类没有默认的构造方法,可是类的声明如下:

@Data
public class InfoDTO {
    
    @Data
    public class TestInfo {
        
    }
}

按理说不会有问题啊。

第二个问题原因

mybatis在构建返回的时候,用的是反射,既然反射新建对象时会报错,那直接new对象的时候会不会也报错。

然后我就去new了一下,然后IDEA提示说缺少静态变量修饰不能直接创建。

所以。。。。

摘了一个大佬调研的解释:

创建非静态内部类对象时,一定要先创建起相应的外部类对象,不能直接创建。

要想在外部能直接创建,就用静态的内部类。

问题解决

将内部类修饰为静态内部类即可。

总结

在使用内部类作为返回对象的时候,需要有两个要点:

  1. 内部类必须有无参构造函数;
  2. 内部类必须为静态类。