mirror of
https://github.com/jlengrand/Exposed.git
synced 2026-03-10 08:11:20 +00:00
created spring boot starter for exposed (#582)
* created spring boot starter for exposed uses spring-boot-starter-data-jdbc ability to autogenerate-ddl using exposed SchemaUtils.Create for any packages that extend Table() spring.exposed.exclude-packages allows you to exclude certain packages uses spring-transaction to enable @Transactional annotation * updated spring-boot version to the latest * added a readme on how to use this library
This commit is contained in:
committed by
Andrey.Tarashevskiy
parent
454959528e
commit
1b951d24cd
55
exposed-spring-boot-starter/README.md
Normal file
55
exposed-spring-boot-starter/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Exposed Spring Boot Starter
|
||||
|
||||
This is a starter for [Spring Boot](https://spring.io/projects/spring-boot) to utilize [Exposed](https://github.com/JetBrains/Exposed) as the ORM instead of [Hibernate](https://hibernate.org/)
|
||||
|
||||
## Getting Started
|
||||
This starter will give you the latest version of [Exposed](https://github.com/JetBrains/Exposed) and the spring-transaction library along with [Spring Boot Data Starter JDBC](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jdbc)
|
||||
### Maven
|
||||
```mxml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jcenter</id>
|
||||
<name>jcenter</name>
|
||||
<url>http://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.exposed</groupId>
|
||||
<artifactId>exposed-spring-boot-starter</artifactId>
|
||||
<version>0.15.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
### Gradle
|
||||
```groovy
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.exposed:exposed-spring-boot-starter:0.15.1'
|
||||
}
|
||||
```
|
||||
|
||||
## Setting up a database connection
|
||||
This starter utilizes spring-boot-starter-data-jdbc so all properties that you are used to for setting up a database in spring are applicable here.
|
||||
|
||||
### application.properties (h2 example)
|
||||
```properties
|
||||
spring.datasource.url=jdbc:h2:mem:testdb
|
||||
spring.datasource.driverClasName=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=password
|
||||
```
|
||||
|
||||
## Automatic Schema Creation
|
||||
This starter will create the database schema if enabled automatically using any class that extends `org.jetbrains.exposed.sql.Table`
|
||||
|
||||
Sometimes you will want to exclude packages from that list, we have included the property `spring.exposed.excluded-packages` which will exclude everything under the provided package
|
||||
|
||||
### application.properties
|
||||
```properties
|
||||
spring.exposed.generate-ddl = true
|
||||
spring.exposed.excluded-packages = com.example.models.ignore,com.example.utils
|
||||
```
|
||||
51
exposed-spring-boot-starter/build.gradle.kts
Normal file
51
exposed-spring-boot-starter/build.gradle.kts
Normal file
@@ -0,0 +1,51 @@
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||
import tanvd.kosogor.proxy.publishJar
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") apply true
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
maven("https://dl.bintray.com/jfrog/jfrog-jars")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":exposed"))
|
||||
api(project(":spring-transaction"))
|
||||
api("org.springframework.boot", "spring-boot-starter-data-jdbc", "2.1.6.RELEASE")
|
||||
api("org.springframework.boot", "spring-boot-autoconfigure", "2.1.6.RELEASE")
|
||||
compileOnly("org.springframework.boot", "spring-boot-configuration-processor", "2.1.6.RELEASE")
|
||||
|
||||
testImplementation("org.springframework.boot", "spring-boot-starter-test", "2.1.6.RELEASE")
|
||||
testImplementation("com.h2database", "h2", "1.4.199")
|
||||
}
|
||||
|
||||
publishJar {
|
||||
publication {
|
||||
artifactId = "exposed-spring-boot-starter"
|
||||
}
|
||||
|
||||
bintray {
|
||||
username = project.properties["bintrayUser"]?.toString() ?: System.getenv("BINTRAY_USER")
|
||||
secretKey = project.properties["bintrayApiKey"]?.toString() ?: System.getenv("BINTRAY_API_KEY")
|
||||
repository = "exposed"
|
||||
info {
|
||||
githubRepo = "https://github.com/JetBrains/Exposed.git"
|
||||
vcsUrl = "https://github.com/JetBrains/Exposed.git"
|
||||
userOrg = "kotlin"
|
||||
license = "Apache-2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Test::class.java) {
|
||||
jvmArgs = listOf("-XX:MaxPermSize=256m")
|
||||
|
||||
testLogging {
|
||||
events.addAll(listOf(TestLogEvent.PASSED, TestLogEvent.FAILED, TestLogEvent.SKIPPED))
|
||||
showStandardStreams = true
|
||||
exceptionFormat = TestExceptionFormat.FULL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.exposed.spring
|
||||
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationPackages
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.util.regex.Pattern
|
||||
|
||||
open class DatabaseInitializer(private val applicationContext: ApplicationContext, private val excludedPackages: List<String>) : ApplicationRunner, Ordered {
|
||||
override fun getOrder(): Int = DATABASE_INITIALIZER_ORDER
|
||||
|
||||
companion object {
|
||||
const val DATABASE_INITIALIZER_ORDER = 0
|
||||
}
|
||||
|
||||
private val logger = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@Transactional
|
||||
override fun run(args: ApplicationArguments?) {
|
||||
val exposedTables = discoverExposedTables(applicationContext, excludedPackages)
|
||||
logger.info("Schema generation for tables '{}'", exposedTables.map { it.tableName })
|
||||
|
||||
logger.info("ddl {}", exposedTables.map { it.ddl }.joinToString())
|
||||
SchemaUtils.create(*exposedTables.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
fun discoverExposedTables(applicationContext: ApplicationContext, excludedPackages: List<String>): List<Table> {
|
||||
val provider = ClassPathScanningCandidateComponentProvider(false)
|
||||
provider.addIncludeFilter(AssignableTypeFilter(Table::class.java))
|
||||
excludedPackages.forEach { provider.addExcludeFilter(RegexPatternTypeFilter(Pattern.compile(it.replace(".", "\\.") + ".*"))) }
|
||||
val packages = AutoConfigurationPackages.get(applicationContext)
|
||||
val components = packages.map { provider.findCandidateComponents(it) }.flatten()
|
||||
return components.map { Class.forName(it.beanClassName).kotlin.objectInstance as Table }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.exposed.spring.autoconfigure
|
||||
|
||||
import org.jetbrains.exposed.spring.DatabaseInitializer
|
||||
import org.jetbrains.exposed.spring.SpringTransactionManager
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement
|
||||
import javax.sql.DataSource
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration::class)
|
||||
@EnableTransactionManagement
|
||||
open class ExposedAutoConfiguration(private val applicationContext: ApplicationContext) {
|
||||
|
||||
@Value("\${spring.exposed.excluded-packages:}#{T(java.util.Collections).emptyList()}")
|
||||
private lateinit var excludedPackages: List<String>
|
||||
|
||||
@Bean
|
||||
open fun springTransactionManager(datasource: DataSource) = SpringTransactionManager(datasource)
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty("spring.exposed.generate-ddl", havingValue="true", matchIfMissing = false)
|
||||
open fun databaseInitializer() = DatabaseInitializer(applicationContext, excludedPackages)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.exposed.generate-ddl",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Auto generate the database schema.",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "spring.exposed.excluded-packages",
|
||||
"type": "java.util.List",
|
||||
"description": "Packages to exclude from schema generation."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.jetbrains.exposed.spring.autoconfigure.ExposedAutoConfiguration
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.exposed.spring
|
||||
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
|
||||
@SpringBootApplication
|
||||
open class Application {
|
||||
|
||||
open fun main(args: Array<String>) {
|
||||
SpringApplication.run(Application::class.java, *args)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.exposed.spring
|
||||
|
||||
|
||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||
import org.jetbrains.exposed.spring.tables.TestTable
|
||||
import org.jetbrains.exposed.spring.tables.ignore.IgnoreTable
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.test.context.junit4.SpringRunner
|
||||
|
||||
@RunWith(SpringRunner::class)
|
||||
@SpringBootTest(classes = [org.jetbrains.exposed.spring.Application::class],
|
||||
properties = ["spring.autoconfigure.exclude=org.jetbrains.exposed.spring.autoconfigure.ExposedAutoConfiguration"])
|
||||
open class DatabaseInitializerTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var applicationContext: ApplicationContext
|
||||
|
||||
@Test(expected = ExposedSQLException::class)
|
||||
fun `should create schema for TestTable and not for IgnoreTable`() {
|
||||
Database.connect("jdbc:h2:mem:test", "org.h2.Driver")
|
||||
transaction {
|
||||
DatabaseInitializer(applicationContext, listOf("org.jetbrains.exposed.spring.tables.ignore")).run(null)
|
||||
Assert.assertEquals(0, TestTable.selectAll().count())
|
||||
IgnoreTable.selectAll().count()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.jetbrains.exposed.spring.autoconfigure
|
||||
|
||||
import org.jetbrains.exposed.spring.DatabaseInitializer
|
||||
import org.jetbrains.exposed.spring.SpringTransactionManager
|
||||
import org.jetbrains.exposed.spring.tables.TestTable
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.test.context.junit4.SpringRunner
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@RunWith(SpringRunner::class)
|
||||
@SpringBootTest(classes = [org.jetbrains.exposed.spring.Application::class],
|
||||
properties = ["spring.datasource.url=jdbc:h2:mem:test", "spring.datasource.driver-class-name=org.h2.Driver"])
|
||||
open class ExposedAutoConfigurationTest {
|
||||
|
||||
@Autowired(required = false)
|
||||
private var springTransactionManager: SpringTransactionManager? = null
|
||||
|
||||
@Autowired(required = false)
|
||||
private var databaseInitializer: DatabaseInitializer? = null
|
||||
|
||||
@Test
|
||||
fun `should initialize the database connection`() {
|
||||
Assert.assertNotNull(springTransactionManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not create schema`() {
|
||||
Assert.assertNull(databaseInitializer)
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringRunner::class)
|
||||
@SpringBootTest(classes = [org.jetbrains.exposed.spring.Application::class],
|
||||
properties = ["spring.datasource.url=jdbc:h2:mem:test", "spring.datasource.driver-class-name=org.h2.Driver","spring.exposed.generate-ddl=true"])
|
||||
open class ExposedAutoConfigurationTestAutoGenerateDDL {
|
||||
|
||||
@Autowired(required = false)
|
||||
private var springTransactionManager: SpringTransactionManager? = null
|
||||
|
||||
@Test
|
||||
fun `should initialize the database connection`() {
|
||||
Assert.assertNotNull(springTransactionManager)
|
||||
}
|
||||
|
||||
@Test @Transactional
|
||||
open fun `should create schema`() {
|
||||
Assert.assertEquals(0, TestTable.selectAll().count())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.exposed.spring.tables
|
||||
|
||||
import org.jetbrains.exposed.dao.IntIdTable
|
||||
|
||||
object TestTable: IntIdTable("test_table") {
|
||||
var name = varchar("name", 100)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.exposed.spring.tables.ignore
|
||||
|
||||
import org.jetbrains.exposed.dao.IntIdTable
|
||||
|
||||
object IgnoreTable: IntIdTable("ignore_table") {
|
||||
var name = varchar("name", 100)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
rootProject.name = "exposed"
|
||||
include("exposed")
|
||||
include("spring-transaction")
|
||||
include("exposed-spring-boot-starter")
|
||||
Reference in New Issue
Block a user