0

I tried creating an event listener like this:

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

. . . but it won't compile. Where the generic type is specified, the compiler returns:

Type argument expected

What am I doing wrong?

Jasper Blues
  • 28,258
  • 22
  • 102
  • 185

2 Answers2

3

The issue is that there are a few possible BeforeSaveEvent classes you could be using. Here are some of the Spring classes mocked out to show you the difference (pay attention to the two BeforeSaveEvent declarations):

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) {}

And so if you code to the Spring data version, your code would be this:

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

If you code to the Neo4j version (which I think you are, because your tags for your question include spring-data-neo4j-4), you have to also specify the entity type parameter:

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
            }
        }
    }
}

So you see exactly what the compiler was asking for:

Please give me a type parameter for BeforeSaveEvent because it is really BeforeSaveEvent<T>

It could be that you imported the wrong class and mean the other BeforeSaveEvent or you imported the correct BeforeSaveEvent<T> and didn't adapt to its actual generic type parameter needs.

Also since ApplicationListener is an interface you don't want () after its use because that means you are trying to call a constructor on an interface.

NOTE: it helps in your questions to provide the declaration signatures of relative classes, from the IDE's perspective (have it click through to find the class you are using, it might not be the one you think you are).

Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
1

Not sure what you wanted to achieve, but a simple fix would be to add the object keyword in the returning statement:

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

object means that you return an object of that class, not a sttrange thing that was in your code. Also I added override since I suspect that onApplicationEvent is a method of ApplicationListener, so it must be overridden.

Actually, if it's ok with you to have only one such an object, you can use object as a singleton dirrectly:

@Bean object beforeSaveEventApplicationListener: ApplicationListener<BeforeSaveEvent>() {
    override fun onApplicationEvent(event: BeforeSaveEvent) {
            //Do something with event
    }
}
Andrey Breslav
  • 24,795
  • 10
  • 66
  • 61
voddan
  • 31,956
  • 8
  • 77
  • 87
  • Thanks for the info, but it still won't compile - at `BeforeSaveEvent` compiler reports 'type argument expected'. The equivalent Java code works fine - I just want to hook save of a neo4j node to allocate a UUID. Could it be a Kotlin compiler issue? I think I'll report it to Jetbrains. – Jasper Blues Oct 29 '15 at 23:42
  • I think the API wants an instance of BeforeSaveEvent to be passed to the constructor invocation – voddan Oct 30 '15 at 02:50
  • The issue is you don't know the declaration of `BeforeSaveEvent`, and the compiler is telling you that it has a generic type parameter. But the code does not provide one. I wrote the details in another answer. – Jayson Minard Jan 07 '16 at 03:33
  • `ApplicationListener` is an interface, not a class. it shouldn't have `()` after it for calling a constructor. – Jayson Minard Jan 07 '16 at 03:37