I try to setup a minimal Apache CXF webapp using SpringBoot3, Kotlin and Gradle, but the single endpoint simply isn't available. All tutorials for Apache CXF & SpringBoot were pretty old, even the official documentation is stuck on Apache CXF 3.1 (current version is 4.0), but according to what i could find, my code looks reasonable.
SpringKotlinInterfaceTestApplication.kt:
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider
import jakarta.ws.rs.*
import org.apache.cxf.Bus
import org.apache.cxf.endpoint.Server
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.stereotype.Component
@Component
@Consumes("application/json")
@Produces("application/json")
class PreconditionApiImpl {
@GET @Path("/pingx")
fun pingx(): String = "{status: OK}"
}
@SpringBootApplication
class SpringKotlinInterfaceTestApplication
fun main(args: Array<String>) {
runApplication<SpringKotlinInterfaceTestApplication>(*args){}
}
@Configuration
class RsConfig {
@Bean
fun getRsServer(bus: Bus, api: PreconditionApiImpl): Server = JAXRSServerFactoryBean().apply {
setBus(bus)
address = "/"
setServiceBeans(listOf(api))
setProvider(
JacksonJsonProvider().apply {
setMapper(ObjectMapper().apply {
registerModule(JodaModule())
setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
})
}
)
}.create()
}
gradle.build.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "3.0.9"
id("io.spring.dependency-management") version "1.0.15.RELEASE"
val kotlinVersion = "1.9.0"
kotlin("jvm") version kotlinVersion
kotlin("plugin.spring") version kotlinVersion
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.jetbrains.kotlin:kotlin-reflect")
val jacksonVersion = "2.14.3"
implementation("com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:$jacksonVersion")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jacksonVersion")
val cxfVersion = "4.0.2"
implementation("org.apache.cxf:cxf-spring-boot-starter-jaxrs:$cxfVersion")
implementation("org.apache.cxf:cxf-rt-rs-client:$cxfVersion")
implementation("org.apache.cxf:cxf-rt-transports-http:$cxfVersion")
implementation("org.apache.cxf:cxf-rt-frontend-jaxws:$cxfVersion")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
jvmTarget = "17"
}
}
Yet a GET to http://localhost:8080/pingx returns a 404.
What am I missing? (maybe cxf-spring-boot-starter-jaxrs doesn't do all the basic wiring after all??)
I figured it out! the configuration is fine! The url was wrong! I have to put an "/services" into it, so it becomes: http://localhost:8080/services/pingx
If I had used a different configuration for the Server address
@Bean fun getRsServer(bus: Bus, api: PreconditionApiImpl): Server = JAXRSServerFactoryBean().apply {
setBus(bus)
address = "/rs"
...
It would be: http://localhost:8080/services/rs/pingx