Announcing: Axon-Kotlin

I’ve been working on a project for the past month or so to make it easier to write Axon code using kotlin.
This is the release of the first module.

Announcing axon-kotlin

Github: https://github.com/snowe2010/axon-kotlin
Central: https://search.maven.org/#search|ga|1|axon-kotlin
Bintray/JCenter: https://bintray.com/snowe/maven/Axon-Kotlin
Documentation: https://snowe2010.github.io/axon-kotlin/axon-kotlin/index.html

This is a library to allow you to write better and easier to read axon-fixture tests. Currently there is only one module axon-kotlin-test but I hope to expand that in the future.

Here are some examples of usage.

Fixture test

`

fixture {
register {
annotatedCommandHandler = MyCommandHandler(fixture.repository, fixture.eventBus)
}
given {
events {
+MyEvent(“aggregateId”, 1)
+MyEvent(“aggregateId”, 2)
+MyEvent(“aggregateId”, 3)
}
}
whenever { StrangeCommand(“aggregateId”) }
expect {
returnValueMatching = DoesMatch()
}
}

`

Saga test

`

val aggregate1 = uuidString()
val aggregate2 = uuidString()
val fixture = SagaTestFixture()
fixture {
given {
aggregate1 published {
+GenericEventMessage.asEventMessage(TriggerSagaStartEvent(aggregate1))
+TriggerExistingSagaEvent(aggregate1)
}
aggregate2 published TriggerSagaStartEvent(aggregate2)
}
whenever {
aggregate1 publishes TriggerSagaEndEvent(aggregate1)
}
expect {
activeSagas = 1
“identifier” associatedWith aggregate2
“identifier” notAssociatedWith aggregate1

scheduledEvent(Duration.ofMinutes(10)).ofType()
scheduledEvent(Duration.ofMinutes(10)).matching(messageWithPayload(any(TimerTriggeredEvent::class.java)))
scheduledEvent(Duration.ofMinutes(10)).of(TimerTriggeredEvent(aggregate1))

scheduledEvent(fixture.currentTime().plusSeconds(600)).ofType()
scheduledEvent(fixture.currentTime().plusSeconds(600)).matching(messageWithPayload(CoreMatchers.any(TimerTriggeredEvent::class.java)))
scheduledEvent(fixture.currentTime().plusSeconds(600)).of(TimerTriggeredEvent(aggregate1))
dispatchedCommands {}
noDispatchedCommands()
publishedEventsMatching(noEvents())
}
}

`

Try it out and let me know what I can improve!

cool idea …

but wouldn’t it be a better idea to have this under the axonframework flag?

I saw it often in the past that helper libs with various usability, focus and maintainability evolved around popular frameworks which lead to the problem that you never could be sure which lib you should use, if it will support the next release and so on …

so +1 for a specialized axon-kotlin support lib, but +2 for having this in the framework or in a framework-extension repo under control of axoniq … the camunda community extension model could serve as a template: https://docs.camunda.org/manual/7.9/introduction/extensions/

I would have liked to put it under the axonframework org, but there were several reasons I didn’t.

  1. I was told by axoniq members that kotlin code wasn’t wanted in the core codebase
  2. Quite a few bits of this library could be deprecated if kotlin code was allowed in the core codebase.
  3. A single individual moves quite a bit faster than an organization.
  4. I believed if I could get users of the library then I could get it to the point where axoniq would maybe allow kotlin in the core codebase. That is the final goal.

So, if axoniq does allow putting kotlin into the main codebase in the future then I think I could move all this code into that codebase and also massively simplify it at the same time.

And thanks for the +1!

Hi Tyler,

thanks for your response and the list of reasons. I didn’t want to blame you or anything, everything you said is true.

I am contributing to the camunda open source process engine, and that’s what we did there:

  • contributions to the core framework follow strict regulations regarding versions, language, style, formatting, … and are maintained and supported on an enterprise level by the core developers, so there is little room for experiments

  • we have a process to create community extensions, those are libs that add additional functionality, helpers and tool to the framework, but are not part of it. Individuals or small teams can contribute and release as they wish, with relatively large freedom regarding implementation, backward-compatibility and so on.

  • those extensions have an “extension” suffix in groupId and package names and are clearly separate from the core framework.

  • the company (camunda) provides infrastructure (ci-server) and deals with maven-central releases.

  • Frans and Allard: if you read this, share your thoughts, please.

As far as I can see, you mainly address fixture testing right now. I myself have a couple of “runtime” support extension functions in my axon/kotlin projects that I’d love to centralize for re-use (mainly dealing with KClass instead of KotlinClass::class.java and inline lambda consumers for callback functions. So I’d be happy to share.

As long as we do not have such a process, I am happy to join forces and will create PRs to your repo with my axon/kotlin stuff. Maybe it would be a good idea to establish a virtual github organization for this.

cu
Jan

Oh no worries Jan,

I didn’t feel like I was being blamed. I would much rather have this in the org. I’ll talk to Steven about this and see what he thinks of your plan. Sounds like a good one to me.

Not that it was a main reason, but another reason I created my own project was because I wanted to learn gradle. Note how I said I had been working on my library for the past month? Most of that was trying to get my library into Maven Central using gradle! haha.

In regards to your extensions bit, I have two packages in the axon-kotlin-test project. one for the dsl and one for the extensions. I am thinking about splitting that out into two separate modules to make it easier to avoid the dsl if you want to. Maybe we can split it into two modules and then stick your extensions stuff alongside the current extensions I’ve written.

Let me talk to Steven before we make a virtual org. He can bug Allard and we can see what he thinks.

Tyler