【问题标题】:Can't create Spring Data Event Listener in Kotlin无法在 Kotlin 中创建 Spring Data 事件侦听器
【发布时间】:2015-10-29 16:16:46
【问题描述】:

我尝试像这样创建一个事件监听器:

@Bean
open fun beforeSaveEventApplicationListener(): ApplicationListener<BeforeSaveEvent>
{
   return ApplicationListener<BeforeSaveEvent>()
   {
       fun onApplicationEvent(event: BeforeSaveEvent)
       {
           //Do something with event
       }
   }
}

。 . .但它不会编译。在指定泛型类型的地方,编译器返回:

Type argument expected

我做错了什么?

【问题讨论】:

标签: java spring spring-data kotlin spring-data-neo4j-4


【解决方案1】:

问题是您可以使用一些可能的BeforeSaveEvent 类。以下是一些模拟出来的 Spring 类以向您展示差异(注意两个 BeforeSaveEvent 声明):

open class ApplicationEvent(source: Any): EventObject(source) {}

interface ApplicationListener<T: ApplicationEvent> {
    fun onApplicationEvent(event: T)
}

// the Spring Data Neo4j version requires a type
class BeforeSaveEvent<T>(source: Any, val entity: T): ApplicationEvent(source) {}

// the Spring data version does not
class BeforeSaveEvent(source: Any): ApplicationEvent(source) {}

因此,如果您对 Spring 数据版本进行编码,您的代码将是这样的:

open class Something {
    open fun beforeSaveEventApplicationListener(): ApplicationListener<BeforeSaveEvent> {
        return object : ApplicationListener<BeforeSaveEvent> {
            override fun onApplicationEvent(event: BeforeSaveEvent) {
                //Do something with event
            }
        }
    }
}

如果您编码到 Neo4j 版本(我认为您是,因为您的问题标签包括 spring-data-neo4j-4),您还必须指定实体类型参数:

class MyEntity {}

open class Something {
    open fun beforeSaveEventApplicationListener(): ApplicationListener<BeforeSaveEvent<MyEntity>> {
        return object : ApplicationListener<BeforeSaveEvent<MyEntity>> {
            override fun onApplicationEvent(event: BeforeSaveEvent<MyEntity>) {
                //Do something with event
            }
        }
    }
}

所以您可以准确地看到编译器的要求:

请给我一个BeforeSaveEvent的类型参数,因为它真的是BeforeSaveEvent&lt;T&gt;

可能是您导入了错误的类并表示另一个 BeforeSaveEvent,或者您导入了正确的 BeforeSaveEvent&lt;T&gt; 并且没有适应其实际的泛型类型参数需求。

另外,由于ApplicationListener 是一个接口,因此在使用() 后您不希望它,因为这意味着您正在尝试调用接口上的构造函数。

注意: 从 IDE 的角度来看,提供相关类的声明签名有助于解决您的问题(让它点击找到您的类正在使用,它可能不是您认为的那样)。

【讨论】:

    【解决方案2】:

    不确定您想要实现什么,但一个简单的解决方法是在返回语句中添加 object 关键字:

    @Bean 
    open fun beforeSaveEventApplicationListener(): ApplicationListener<BeforeSaveEvent> 
    {
        return object : ApplicationListener<BeforeSaveEvent>()
        {
            override fun onApplicationEvent(event: BeforeSaveEvent)
            {
                //Do something with event
            }
        }
    }
    

    object 表示您返回该类的对象,而不是代码中的奇怪事物。我还添加了override,因为我怀疑onApplicationEventApplicationListener 的方法,所以它必须被覆盖。

    实际上,如果你可以只拥有一个这样的对象,你可以直接将object 用作单例:

    @Bean object beforeSaveEventApplicationListener: ApplicationListener<BeforeSaveEvent>() {
        override fun onApplicationEvent(event: BeforeSaveEvent) {
                //Do something with event
        }
    }
    

    【讨论】:

    • 感谢您的信息,但它仍然无法编译 - BeforeSaveEvent 编译器报告“预期类型参数”。等效的 Java 代码工作正常 - 我只想挂钩保存 neo4j 节点以分配 UUID。会不会是 Kotlin 编译器的问题?我想我会向 Jetbrains 报告。
    • 我认为 API 希望将 BeforeSaveEvent 的实例传递给构造函数调用
    • 问题是你不知道BeforeSaveEvent的声明,编译器告诉你它有一个泛型类型参数。但是代码没有提供一个。我在另一个答案中写了详细信息。
    • ApplicationListener 是一个接口,而不是一个类。它后面不应该有 () 来调用构造函数。
    猜你喜欢
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多