Blog · Loji44AboutTAGSRSS🔍SEARCH

JDK1.8之前,我们通过反射获取一个方法定义的参数名称时,无法获取到真实的参数名称,例如:

public class SomeClass {
    public String func(String nickName, Integer age) {
        return "something to be return";
    }
}

在类编译之后,类的方法参数名称会丢失,通过反射机制获取到的参数名称变成了arg0arg1这样的。有些场景例如MyBatis这种通过反射来获取Mapper接口上方法参数然后映射到XML的SQL语句上,就没法直接用:

@Mapper
public interface SomeMapper {
    SomePojo selectOne(String nickName, String mobile);
}

XML文件如下:

<select id="selectOne" resultMap="resultMap">
    SELECT * FROM `some_table` WHERE nick_name = #{nickName} AND mobile = #{mobile};
</select>

MyBatis通过反射获取到的参数名称其实是:nickName -> arg0mobile -> arg1 这样就没法正确映射到XML的SQL中#{nickName}#{mobile}

所以需要使用@Param注解来告诉MyBatis参数的真实名称,MyBatis才能正确映射参数:

@Mapper
public interface SomeMapper {
    SomePojo selectOne(@Param("nickName") String nickName, @Param("mobile") String mobile);
}

JDK1.8之后,除了通过在参数上打注解的方式,Java原生的反射机制新增了一个类用于描述方法上的参数:java.lang.reflect.Parameter。我们可以直接通过这个反射类获取到方法参数的真实名称。

前提是我们需要在编译的时候加入-parameter参数,让编译器在编译类的时候将方法的参数名称也打包到.class文件里面。默认情况下-parameter是关闭的,如果需要此功能,需要手动开启:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <compilerArgs>
            <compilerArg>-parameters</compilerArg>
        </compilerArgs>
    </configuration>
</plugin>

这样之后,就算我们不在参数上打@Param注解,MyBatis也能获取到真实的参数名称nickNamemobile


参考: