Skip to main content
ElastiCORE 3.0 is a release candidate: 3.0.261022-rc1 on Maven Central. Projects on the 2.2 line: see the 2.2 documentation.
Version: 3.0

Java and Kotlin

language = 'kotlin' generates the same model as Kotlin entities, services and controllers in src/main/kotlin, with the -kt edition of the chosen bundle (jpa-springboot-kt, ddd-springboot-kt, hexagonal-springboot-kt). The rules are shared; only how each language says it differs.

build.gradle
elasticore {
architecture = 'hexagonal'
language = 'kotlin' // java | kotlin
}

The same lifecycle in both languages​

The Ticket of the Kotlin sample has two lifecycles, and its cancel command moves both:

blueprint/shop/model/ticket.yml (elasticore-template-kt)
  Ticket:
meta: entity @root @expose(20) @owner(agentId) @access(read=owner, create=user, close=owner) @event(Closed) -- 작업
TicketBase.kt
    open fun cancel() {
requireStatus("cancel", TicketStatus.OPEN)
requireBilling("cancel", BillingStatus.UNBILLED)
this.status = TicketStatus.CLOSED
this.billing = BillingStatus.VOID
raiseClosed()
}

/** Whether cancel may be given now: the status is OPEN and the billing is UNBILLED. */
fun canCancel(): Boolean = (this.status == TicketStatus.OPEN) && (this.billing == BillingStatus.UNBILLED)

What differs​

JavaKotlin
Event classesfields + constructor + gettersvals of the primary constructor (data class)
Specificationsprivate constructorobject
Factoriesprivate constructor + staticobject + fun
Ports of domain services and process managers@Autowired protected field on XxxBase@Autowired protected lateinit var
Conditionsorder.getItems()order.items!!
Invariant listeners@EntityListeners({A.class, B.class})@EntityListeners(A::class, B::class)
Value objectsimmutable through Lombokimmutable through the language
Sealed setters@Setter(AccessLevel.PROTECTED)protected set / final var ... private set
Signaturesnullability matches the service (save(dto: OrderDTO): OrderDTO?)

A rule that only one language has says so (requireSyntax) and stops with the reason when selected for the other - Java never ends up silently inside a .kt file.

What a Kotlin build needs​

The Kotlin plugins a Kotlin JPA project applies, as in elasticore-template-kt (the sample takes the io.elasticore plugin from the repository itself; a project names the released version):

build.gradle
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.9.24'
id 'org.jetbrains.kotlin.plugin.allopen' version '1.9.24'
id 'org.jetbrains.kotlin.plugin.jpa' version '1.9.24'
id 'io.spring.dependency-management' version '1.1.6'
id 'io.elasticore' version '3.0.261022-rc1'
}
  • org.jetbrains.kotlin:kotlin-reflect - a Kotlin application on Spring needs it.
  • With Spring Boot 4: Kotlin 2.2 or later, and the Jackson Kotlin module is tools.jackson.module:jackson-module-kotlin.
  • The generated code boots without the kotlin-spring plugin: extension services and repository adapters are open class, and entity collections are MutableList<X>.
  • mapping: xml (JPA annotations moved to orm.xml): register io.elasticore.springboot3.entity.PersistentModel with allOpen and noArg.
  • `in` - the hexagonal package adapter.in.web is written with the keyword escaped.

Where each reaches​

Most rules reach both languages. @search(like) is case-insensitive in every Kotlin build (and in the v3 Java bundles); @restExclude removes methods from the Kotlin controller and use case while the Kotlin service keeps them.

Sample: elasticore-template-kt - generated, compiled and started on every build (ShopApiContractTest).