JUnit中双冒号运算符调用非公开方法报错排查
问题分析与解决
核心问题在于方法引用(::)和Lambda表达式在JVM权限检查上的处理逻辑不同:
- Lambda表达式会被编译为匿名类,它对目标方法的调用走常规路径,Spring Data的代理或测试框架的字节码增强可以覆盖这个调用,放宽权限检查。
- 方法引用则直接绑定到原始方法的句柄,JVM会严格校验该方法的访问权限——因为
UserRepositoryInternal.findOneWithAuthoritiesById是非公开方法,而dap-java-run运行时没有加载Gradle测试环境中的权限放宽逻辑,所以触发IllegalAccessException。
为什么Gradle运行测试正常?
Gradle执行测试时,通常会集成Spring Data的代理生成机制(比如CGLIB),或是测试框架(如JUnit 5)通过字节码增强工具(如ASM)修改类的访问权限,让非公开方法能被合法调用。但dap-java-run默认可能没加载这些增强逻辑,导致权限检查严格生效。
解决方案
- 修改方法权限:把
UserRepositoryInternal.findOneWithAuthoritiesById改成public修饰符,这是最彻底的方案,符合Java访问权限规范。 - 同步JVM配置:通过
./gradlew test --info查看Gradle测试任务的JVM参数,把相关的字节码增强、代理生成参数添加到DAP的运行配置中,确保和Gradle测试环境一致。 - 临时替代:继续用Lambda表达式替换方法引用,这种方式能绕过JVM对方法引用的直接权限检查,快速恢复测试运行。
调试方向
- 对比Gradle测试和
dap-java-run的JVM启动参数,排查是否缺少代理或增强相关的关键参数。 - 检查Emacs中lsp-java的DAP调试配置,确认是否启用了Spring相关的代理支持。
- 用
javap反编译测试类,对比方法引用和Lambda生成的字节码差异,直观理解权限检查的触发点。
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

