简体   繁体   English

Spring Proxy Class和Kotlin中的空指针异常

[英]Null Pointer Exception In Spring Proxy Class and Kotlin

I am facing some problems with kotlin in conjunction with spring. 我和kotlin一起面临春天的问题。

I have a controller bean (without an interface btw) which has an auto-wired service bean via the primary constructor. 我有一个控制器bean(没有接口btw),它通过主构造函数有一个自动连接的服务bean。

It works perfectly unless I use caching annotations for the controller. 除非我为控制器使用缓存注释,否则它工作正常。 Apparently springs caching generates a proxy class under the hood which deals with the caching. 显然,spring缓存会在引擎盖下生成一个代理类来处理缓存。

My code looks like this: 我的代码看起来像这样:

@RestController
@RequestMapping("/regions/")
open class RegionController @Autowired constructor(val service: RegionService) {
    @RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
    @Cacheable(cacheNames = arrayOf("regions"))
    fun get(@PathVariable id: Long): RegionResource {
        return this.service.get(id)
    }
}

The problem now is a null pointer exception when the method is executed, actually this.service is null which technically is not possible as it is a nonnull variable in kotlin. 现在问题是在执行方法时出现空指针异常,实际上this.servicenull ,这在技术上是不可能的,因为它是kotlin中的非null变量。

I assume that class proxies generated by spring initialize the class with null values instead of the autowired bean. 我假设spring生成的类代理用null值而不是autowired bean初始化类。 This must be a common pitfall using kotlin and spring. 这必须是使用kotlin和spring的常见陷阱。 How did you circumvent this problem? 你是怎么绕过这个问题的?

In Kotlin both classes and members are final by default. 在Kotlin ,默认情况下, 班级和成员都是最终的。

For the proxying library ( CGLIB , javaassist ) to be able to proxy a method it has to be declared non final and in a non final class ( since those libraries implement proxying by subclassing ). 对于能够代理方法的代理库( CGLIBjavaassist ),它必须被声明为非final非final类( 因为这些库通过子类实现代理 )。 Change your controller method to: 将您的控制器方法更改为:

@RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
@Cacheable(cacheNames = arrayOf("regions"))
open fun get(@PathVariable id: Long): RegionResource {
    return this.service.get(id)
}

You probably see a warning in console regarding RegionController methods not being subject to proxying. 您可能会在控制台中看到有关RegionController方法不受代理约束的警告。

The Kotlin compiler plugin Kotlin编译器插件

The Kotlin team has acknowledged this difficulty and created a plugin that marks the standard AOP proxy candidates eg @Component with open . Kotlin团队承认了这一困难并创建了一个插件,标志着标准的AOP代理候选者,例如@Component with open

You can enable the plugin by in your build.gradle : 您可以在build.gradle启用插件:

plugins {
  id "org.jetbrains.kotlin.plugin.spring" version "1.1.60"
}

Soon this might not be a problem any longer. 很快,这可能不再是一个问题。

There is work in progress that any lib (including spring for example) can specify a list of annotations a file in META-INF. 正在进行的工作中,任何lib(包括spring)都可以在META-INF中指定文件的注释列表。 Once a class is annotated with one of these, it will default to open for the class itself and all its functions. 一旦用其中一个类注释了类,它将默认为类本身及其所有函数打开。 This is also true for classes inheriting from an annotated class. 对于从带注释的类继承的类也是如此。

For more details, have a look at https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204 有关更多详细信息,请查看https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM