Trying to use the following DSL for my Spring Boot 3.4 project and my build.gradle.kts has the following - it complains that it cannot find filesMatching
or expand
methods here.
tasks.named("processResources") {
filesMatching("application.properties") {
expand(project.properties)
}
}
What plugins do I need? I have this:
plugins {
id("io.spring.dependency-management") version "1.1.7"
id("org.springframework.boot") version "3.4.4"
id("org.owasp.dependencycheck") version "12.1.0"
kotlin("jvm") version "1.9.23"
kotlin("plugin.spring") version "1.9.23"
}
How do I get these methods available here?
demo-kotlin-app
├── settings.gradle.kts
├── build.gradle.kts
├── gradle.properties
└── src
└── main
├── kotlin
│ └── com
│ └── example
│ ├── DemoKotlinAppApplication.kt
│ ├── model
│ │ └── Person.kt
│ ├── repository
│ │ └── PersonRepository.kt
│ ├── service
│ │ └── PersonService.kt
│ └── controller
│ └── PersonController.kt
└── resources
├── application.properties
└── logback-spring.xml
The contents of this file are the default settings, they have not been changed and are not important.
rootProject.name = "demo-kotlin-app"
plugins {
kotlin("jvm") version "1.9.25"
kotlin("plugin.spring") version "1.9.25"
id("org.springframework.boot") version "3.4.4"
id("io.spring.dependency-management") version "1.1.7"
kotlin("plugin.jpa") version "1.9.25"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springframework.boot:spring-boot-starter-logging")
implementation("com.mysql:mysql-connector-j")
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}
allOpen {
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
}
tasks.named<ProcessResources>("processResources") {
filesMatching("application.properties") {
expand(project.properties)
}
}
Note:
My Config:
tasks.named<ProcessResources>("processResources")
tasks.named<ProcessResources>("processResources") {
filesMatching("application.properties") {
expand(project.properties)
}
}
Your Config:
tasks.named("processResources")
tasks.named("processResources") {
filesMatching("application.properties") {
expand(project.properties)
}
}
The settings in this file are configured to be used with expand(project.properties)
, which converts the ${XXX}
placeholders in the application.properties
file.
serverPort=8080
databaseUrl=jdbc:mysql://localhost:3306/demodb
jdbcDriver=com.mysql.cj.jdbc.Driver
databaseUser=demouser
databasePassword=Passw0rd!
dialect=org.hibernate.dialect.MySQL8Dialect
package com.example
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class DemoKotlinAppApplication
fun main(args: Array<String>) {
runApplication<DemoKotlinAppApplication>(*args)
}
package com.example.model
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
@Entity
data class Person(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String,
val email: String
)
package com.example.repository
import com.example.model.Person
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface PersonRepository : JpaRepository<Person, Long> {
fun findByNameContaining(name: String): List<Person>
}
package com.example.service
import com.example.model.Person
import com.example.repository.PersonRepository
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class PersonService(private val personRepository: PersonRepository) {
private val logger: Logger = LoggerFactory.getLogger(PersonService::class.java)
fun getAllPersons(): List<Person> {
logger.debug("Fetching all persons from the database")
return personRepository.findAll()
}
fun getPersonById(id: Long): Person? {
logger.debug("Fetching person with ID: $id")
return personRepository.findById(id).orElse(null)
}
fun createPerson(name: String, email: String): Person {
logger.debug("Creating person with name: $name and email: $email")
val person = Person(name = name, email = email)
return personRepository.save(person)
}
fun getPersonsByName(name: String): List<Person> {
logger.debug("Searching for persons with name containing: $name")
return personRepository.findByNameContaining(name)
}
}
package com.example.controller
import com.example.model.Person
import com.example.service.PersonService
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/persons")
class PersonController(private val personService: PersonService) {
private val logger: Logger = LoggerFactory.getLogger(PersonController::class.java)
@GetMapping
fun getAllPersons(): List<Person> {
logger.info("Fetching all persons")
return personService.getAllPersons()
}
@GetMapping("/{id}")
fun getPersonById(@PathVariable id: Long): Person? {
logger.info("Fetching person with ID: $id")
return personService.getPersonById(id)
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun createPerson(@RequestBody person: Person): Person {
logger.info("Creating new person: ${person.name}")
return personService.createPerson(person.name, person.email)
}
@GetMapping("/search")
fun getPersonsByName(@RequestParam name: String): List<Person> {
logger.info("Searching persons with name: $name")
return personService.getPersonsByName(name)
}
}
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="INFO"/>
<logger name="com.example" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
The ${XXXX}
placeholders in this file will be replaced with the contents of the gradle.properties file using expand(project.properties)
.
spring.application.name=demo-kotlin-app
server.port=${serverPort}
spring.datasource.url=${databaseUrl}
spring.datasource.username=${databaseUser}
spring.datasource.password=${databasePassword}
spring.datasource.driver-class-name=${jdbcDriver}
spring.jpa.database-platform=${dialect}
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type.descriptor.sql.BasicBinder.log.level=TRACE
logging.level.org.springframework=INFO
logging.level.com.example=DEBUG
logging.level.root=INFO
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
My build instructions are as follows:
gradle clean build
This example requires MySQL, and its configuration is as follows:
jdbc:mysql://localhost:3306/demodb
demouser
Passw0rd!
Before executing the following commands, make sure that MySQL is running.
java -jar build/libs/demo-kotlin-app-0.0.1-SNAPSHOT.jar
curl -X POST http://localhost:8080/persons \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john.doe@example.com"
}'
curl -X GET http://localhost:8080/persons
curl -X GET http://localhost:8080/persons/1
unzip demo-kotlin-app-0.0.1-SNAPSHOT.jar (demo-kotlin-app/build/libs/demo-kotlin-app-0.0.1-SNAPSHOT.jar)
demo-kotlin-app/build/libs/demo-kotlin-app-0.0.1-SNAPSHOT/BOOT-INF/classes
This file's ${XXXX}
content has been converted, and it appears as expected.
spring.application.name=demo-kotlin-app
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/demodb
spring.datasource.username=demouser
spring.datasource.password=Passw0rd!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type.descriptor.sql.BasicBinder.log.level=TRACE
logging.level.org.springframework=INFO
logging.level.com.example=DEBUG
logging.level.root=INFO
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
$ gradle -v
------------------------------------------------------------
Gradle 8.10
------------------------------------------------------------
Build time: 2024-08-14 11:07:45 UTC
Revision: fef2edbed8af1022cefaf44d4c0514c5f89d7b78
Kotlin: 1.9.24
Groovy: 3.0.22
Ant: Apache Ant(TM) version 1.10.14 compiled on August 16 2023
Launcher JVM: 17.0.12 (Eclipse Adoptium 17.0.12+7)
Daemon JVM: /home/demo/.sdkman/candidates/java/17.0.12-tem (no JDK specified, using current Java home)
OS: Linux 6.8.0-57-generic amd64