I have an example SpringBoot app in Kotlin and WebFlux. I divided whole application into modules (as I'm used to from asp.net).
Modules:
My problem now is how to properly work with ReactiveCrudRepository<> and repositories in general. I have config class in data module to enable R2dbcRepositories.
@Configuration
@EnableR2dbcRepositories("me.janam.data")
open class RepositoriesConfiguration {
}
Now if I create table and repository
interface IPersonRepository: ReactiveCrudRepository<PersonTable, Long> {
@Query("SELECT * FROM person.person limit 1")
fun getOne(): Mono<PersonTable>
}
and try to use it in business module I'm getting an error
Cannot access 'org.springframework.data.repository.reactive.ReactiveCrudRepository' which is a supertype of 'me.janam.data.features.person.repositories.IPersonRepository'. Check your module classpath for missing or conflicting dependencies
Of course if I add
implementation("org.springframework.data:spring-data-commons:2.4.6")
into my business module everything works fine. But somehow this feels strange to me. Is this the right way how to do this?
Also not part of my main question but here is complete config and I like to hear some opinion on it as i'm mainly asp.net dev. Thx.
root - settings.gradle.kts:
rootProject.name = "springboot-example"
include(":api")
include(":business")
include(":data")
include(":core")
root - gradle.properties:
kotlin.code.style=official
kotlin_version=1.4.31
kotlinx_coroutines_reactor_version=1.4.3
r2dbc_postgresql_version=0.8.7.RELEASE
postgresql_version=42.2.19
spring_context_version=5.3.5
root - build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.4.31"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
subprojects {
apply(plugin = "io.spring.dependency-management" )
dependencyManagement {
}
}
group = "me.janam"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
//implementation("org.springframework:spring-context:5.3.5")
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "13"
}
core - build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
}
group = "me.janam"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "13"
}
data - build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val kotlinx_coroutines_reactor_version: String by project
val r2dbc_postgresql_version: String by project
val postgresql_version: String by project
val spring_context_version: String by project
plugins {
kotlin("jvm")
}
group = "me.janam"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(project(":core"))
implementation("org.springframework:spring-context:$spring_context_version")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc:2.4.4")
runtimeOnly("io.r2dbc:r2dbc-postgresql:$r2dbc_postgresql_version")
runtimeOnly("org.postgresql:postgresql:$postgresql_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinx_coroutines_reactor_version")
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "13"
}
business - build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val kotlinx_coroutines_reactor_version: String by project
val spring_context_version: String by project
plugins {
kotlin("jvm")
}
group = "me.janam"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(project(":core"))
implementation(project(":data"))
implementation("org.springframework:spring-context:$spring_context_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinx_coroutines_reactor_version")
implementation("org.springframework.data:spring-data-commons:2.4.6") //TODO
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "13"
}
api - build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.4.4"
// Přesunuto do rootu
id("io.spring.dependency-management")
kotlin("jvm")
kotlin("plugin.spring") version "1.4.31"
}
group = "me.janam"
version = "1.0-SNAPSHOT"
//java.sourceCompatibility = JavaVersion.VERSION_13
repositories {
mavenCentral()
}
dependencies {
implementation(project(":core"))
implementation(project(":business"))
//implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
implementation("org.springframework.boot:spring-boot-starter-rsocket")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
//runtimeOnly("io.r2dbc:r2dbc-postgresql")
//runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "13"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
Adding the same set of dependencies to each subproject may feel odd, but it's totally fine to do. In order to use a given dependency in a given subproject, you'll have to specify it as a dependency for that subproject.
There are, however, neater ways to accomplish this than actually copy-pasting the import statement to each build file. I would suggest specifying a subprojects
section in your root build.gradle.kts
and putting shared & common dependencies there:
subprojects {
dependencies {
// Put items here that are used in all/most subprojects:
implementation("org.springframework:spring-context:$spring_context_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinx_coroutines_reactor_version")
// You can put this import here or just keep it in the build files
// for subprojects where it will actually get used
implementation("org.springframework.data:spring-data-commons:2.4.6")
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
}
}
You'll still need to specify in each sub-build file what other subprojects each depends on with implementation(project(":core"))
type statements, but the above dependencies
block takes care of making the specified libraries accessible in all subprojects.