mirror of
https://github.com/Dannecron/spring-boot-demo.git
synced 2025-12-26 08:42:33 +03:00
move validation to separate core package, add generation service
some code cleanup
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
package com.github.dannecron.demo.config.properties
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ConfigurationProperties("validation")
|
||||
data class ValidationProperties(
|
||||
val schema: Map<String, String>
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.github.dannecron.demo.models
|
||||
|
||||
import com.github.dannecron.demo.models.serializables.OffsetDateTimeSerialization
|
||||
import com.github.dannecron.demo.models.serializables.UuidSerialization
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.relational.core.mapping.Column
|
||||
import org.springframework.data.relational.core.mapping.Table
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Table("city")
|
||||
@Serializable
|
||||
data class City(
|
||||
@Id
|
||||
val id: Long?,
|
||||
@Serializable(with = UuidSerialization::class)
|
||||
val guid: UUID,
|
||||
val name: String,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "created_at")
|
||||
val createdAt: OffsetDateTime,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "updated_at")
|
||||
val updatedAt: OffsetDateTime?,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "deleted_at")
|
||||
val deletedAt: OffsetDateTime?,
|
||||
) {
|
||||
fun isDeleted(): Boolean = deletedAt != null
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.github.dannecron.demo.models
|
||||
|
||||
import com.github.dannecron.demo.models.serializables.OffsetDateTimeSerialization
|
||||
import com.github.dannecron.demo.models.serializables.UuidSerialization
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.relational.core.mapping.Column
|
||||
import org.springframework.data.relational.core.mapping.Table
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Table("customer")
|
||||
@Serializable
|
||||
data class Customer(
|
||||
@Id
|
||||
val id: Long?,
|
||||
@Serializable(with = UuidSerialization::class)
|
||||
val guid: UUID,
|
||||
val name: String,
|
||||
val cityId: Long?,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "created_at")
|
||||
val createdAt: OffsetDateTime,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "updated_at")
|
||||
val updatedAt: OffsetDateTime?,
|
||||
)
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.github.dannecron.demo.models
|
||||
|
||||
import com.github.dannecron.demo.db.entity.City
|
||||
import com.github.dannecron.demo.db.entity.Customer
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.dannecron.demo.models.order
|
||||
package com.github.dannecron.demo.models
|
||||
|
||||
import com.github.dannecron.demo.models.Product
|
||||
import com.github.dannecron.demo.db.entity.Product
|
||||
import com.github.dannecron.demo.db.entity.order.Order
|
||||
|
||||
data class OrderWithProducts(
|
||||
val order: Order,
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.github.dannecron.demo.models
|
||||
|
||||
|
||||
import com.github.dannecron.demo.models.serializables.OffsetDateTimeSerialization
|
||||
import com.github.dannecron.demo.models.serializables.UuidSerialization
|
||||
import com.github.dannecron.demo.utils.roundTo
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.relational.core.mapping.Column
|
||||
import org.springframework.data.relational.core.mapping.Table
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Table(value = "product")
|
||||
@Serializable
|
||||
data class Product(
|
||||
@Id
|
||||
val id: Long?,
|
||||
@Serializable(with = UuidSerialization::class)
|
||||
val guid: UUID,
|
||||
val name: String,
|
||||
val description: String?,
|
||||
val price: Long,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "created_at")
|
||||
val createdAt: OffsetDateTime,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "updated_at")
|
||||
val updatedAt: OffsetDateTime?,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "deleted_at")
|
||||
val deletedAt: OffsetDateTime?,
|
||||
) {
|
||||
fun getPriceDouble(): Double = (price.toDouble() / 100).roundTo(2)
|
||||
|
||||
fun isDeleted(): Boolean = deletedAt != null
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.github.dannecron.demo.models.order
|
||||
|
||||
import com.github.dannecron.demo.models.serializables.OffsetDateTimeSerialization
|
||||
import com.github.dannecron.demo.models.serializables.UuidSerialization
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.relational.core.mapping.Column
|
||||
import org.springframework.data.relational.core.mapping.Table
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Table(value = "order")
|
||||
@Serializable
|
||||
data class Order(
|
||||
@Id
|
||||
val id: Long?,
|
||||
@Serializable(with = UuidSerialization::class)
|
||||
val guid: UUID,
|
||||
val customerId: Long,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "delivered_at")
|
||||
val deliveredAt: OffsetDateTime?,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "created_at")
|
||||
val createdAt: OffsetDateTime,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "updated_at")
|
||||
val updatedAt: OffsetDateTime?
|
||||
) {
|
||||
fun isDelivered(): Boolean = deliveredAt != null
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.github.dannecron.demo.models.order
|
||||
|
||||
import com.github.dannecron.demo.models.serializables.OffsetDateTimeSerialization
|
||||
import com.github.dannecron.demo.models.serializables.UuidSerialization
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.annotation.Transient
|
||||
import org.springframework.data.domain.Persistable
|
||||
import org.springframework.data.relational.core.mapping.Column
|
||||
import org.springframework.data.relational.core.mapping.Table
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Table(value = "order_product")
|
||||
@Serializable
|
||||
data class OrderProduct(
|
||||
@Id
|
||||
@Serializable(with = UuidSerialization::class)
|
||||
val guid: UUID,
|
||||
@Column(value = "order_id")
|
||||
val orderId: Long,
|
||||
@Column(value = "product_id")
|
||||
val productId: Long,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "created_at")
|
||||
val createdAt: OffsetDateTime,
|
||||
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||
@Column(value = "updated_at")
|
||||
val updatedAt: OffsetDateTime?,
|
||||
): Persistable<UUID> {
|
||||
@Transient
|
||||
var isNewInstance: Boolean? = null
|
||||
|
||||
override fun getId(): UUID {
|
||||
return guid
|
||||
}
|
||||
|
||||
override fun isNew(): Boolean {
|
||||
return isNewInstance ?: true
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.github.dannecron.demo.models.serializables
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
object OffsetDateTimeSerialization: KSerializer<OffsetDateTime> {
|
||||
override val descriptor = PrimitiveSerialDescriptor("Time", PrimitiveKind.STRING)
|
||||
|
||||
override fun deserialize(decoder: Decoder): OffsetDateTime = OffsetDateTime.parse(decoder.decodeString())
|
||||
|
||||
override fun serialize(encoder: Encoder, value: OffsetDateTime) {
|
||||
encoder.encodeString(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.github.dannecron.demo.models.serializables
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.util.*
|
||||
|
||||
object UuidSerialization: KSerializer<UUID> {
|
||||
override val descriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
|
||||
|
||||
override fun deserialize(decoder: Decoder): UUID = UUID.fromString(decoder.decodeString())
|
||||
|
||||
override fun serialize(encoder: Encoder, value: UUID) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.dannecron.demo.services.database.city
|
||||
|
||||
import com.github.dannecron.demo.models.City
|
||||
import com.github.dannecron.demo.db.entity.City
|
||||
import com.github.dannecron.demo.services.database.exceptions.CityNotFoundException
|
||||
import com.github.dannecron.demo.services.database.exceptions.AlreadyDeletedException
|
||||
import com.github.dannecron.demo.services.kafka.dto.CityCreateDto
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
package com.github.dannecron.demo.services.database.city
|
||||
|
||||
import com.github.dannecron.demo.models.City
|
||||
import com.github.dannecron.demo.providers.CityRepository
|
||||
import com.github.dannecron.demo.core.services.generation.CommonGenerator
|
||||
import com.github.dannecron.demo.db.entity.City
|
||||
import com.github.dannecron.demo.db.repository.CityRepository
|
||||
import com.github.dannecron.demo.services.database.exceptions.AlreadyDeletedException
|
||||
import com.github.dannecron.demo.services.database.exceptions.CityNotFoundException
|
||||
import com.github.dannecron.demo.services.kafka.dto.CityCreateDto
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class CityServiceImpl(
|
||||
private val cityRepository: CityRepository
|
||||
private val cityRepository: CityRepository,
|
||||
private val commonGenerator: CommonGenerator,
|
||||
): CityService {
|
||||
override fun findByGuid(guid: UUID): City? = cityRepository.findByGuid(guid)
|
||||
|
||||
override fun create(name: String): City = City(
|
||||
id = null,
|
||||
guid = UUID.randomUUID(),
|
||||
guid = commonGenerator.generateUUID(),
|
||||
name = name,
|
||||
createdAt = OffsetDateTime.now(),
|
||||
createdAt = commonGenerator.generateCurrentTime(),
|
||||
updatedAt = null,
|
||||
deletedAt = null,
|
||||
).let {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.dannecron.demo.services.database.customer
|
||||
|
||||
import com.github.dannecron.demo.models.Customer
|
||||
import com.github.dannecron.demo.db.entity.Customer
|
||||
import com.github.dannecron.demo.models.CustomerExtended
|
||||
import com.github.dannecron.demo.services.database.exceptions.CityNotFoundException
|
||||
import java.util.*
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package com.github.dannecron.demo.services.database.customer
|
||||
|
||||
import com.github.dannecron.demo.models.Customer
|
||||
import com.github.dannecron.demo.core.services.generation.CommonGenerator
|
||||
import com.github.dannecron.demo.db.entity.Customer
|
||||
import com.github.dannecron.demo.db.repository.CityRepository
|
||||
import com.github.dannecron.demo.db.repository.CustomerRepository
|
||||
import com.github.dannecron.demo.models.CustomerExtended
|
||||
import com.github.dannecron.demo.providers.CityRepository
|
||||
import com.github.dannecron.demo.providers.CustomerRepository
|
||||
import com.github.dannecron.demo.services.database.exceptions.CityNotFoundException
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class CustomerServiceImpl(
|
||||
private val customerRepository: CustomerRepository,
|
||||
private val cityRepository: CityRepository
|
||||
private val cityRepository: CityRepository,
|
||||
private val commonGenerator: CommonGenerator,
|
||||
): CustomerService {
|
||||
override fun findByGuid(guid: UUID): CustomerExtended? = customerRepository.findByGuid(guid)
|
||||
?.let {
|
||||
@@ -22,12 +25,12 @@ class CustomerServiceImpl(
|
||||
|
||||
override fun create(name: String, cityGuid: UUID?): Customer = Customer(
|
||||
id = null,
|
||||
guid = UUID.randomUUID(),
|
||||
guid = commonGenerator.generateUUID(),
|
||||
name = name,
|
||||
cityId = cityGuid?.let {
|
||||
cityRepository.findByGuid(it)?.id ?: throw CityNotFoundException()
|
||||
},
|
||||
createdAt = OffsetDateTime.now(),
|
||||
createdAt = commonGenerator.generateCurrentTime(),
|
||||
updatedAt = null,
|
||||
).let {
|
||||
customerRepository.save(it)
|
||||
|
||||
@@ -1,55 +1,65 @@
|
||||
package com.github.dannecron.demo.services.database.order
|
||||
|
||||
import com.github.dannecron.demo.models.Customer
|
||||
import com.github.dannecron.demo.models.Product
|
||||
import com.github.dannecron.demo.models.order.Order
|
||||
import com.github.dannecron.demo.models.order.OrderProduct
|
||||
import com.github.dannecron.demo.models.order.OrderWithProducts
|
||||
import com.github.dannecron.demo.providers.OrderProductRepository
|
||||
import com.github.dannecron.demo.providers.OrderRepository
|
||||
import com.github.dannecron.demo.providers.ProductRepository
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import com.github.dannecron.demo.core.services.generation.CommonGenerator
|
||||
import com.github.dannecron.demo.db.entity.Customer
|
||||
import com.github.dannecron.demo.db.entity.Product
|
||||
import com.github.dannecron.demo.db.entity.order.Order
|
||||
import com.github.dannecron.demo.db.entity.order.OrderProduct
|
||||
import com.github.dannecron.demo.db.repository.OrderProductRepository
|
||||
import com.github.dannecron.demo.db.repository.OrderRepository
|
||||
import com.github.dannecron.demo.db.repository.ProductRepository
|
||||
import com.github.dannecron.demo.models.OrderWithProducts
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@Service
|
||||
class OrderServiceImpl(
|
||||
@Autowired private val orderRepository: OrderRepository,
|
||||
@Autowired private val orderProductRepository: OrderProductRepository,
|
||||
@Autowired private val productRepository: ProductRepository,
|
||||
private val orderRepository: OrderRepository,
|
||||
private val orderProductRepository: OrderProductRepository,
|
||||
private val productRepository: ProductRepository,
|
||||
private val commonGenerator: CommonGenerator,
|
||||
) {
|
||||
fun getByCustomerId(customerId: Long): List<OrderWithProducts> = orderRepository.findByCustomerId(customerId)
|
||||
fun findByCustomerId(customerId: Long): List<OrderWithProducts> = orderRepository.findByCustomerId(customerId)
|
||||
.let { orders -> orders.map { order -> OrderWithProducts(
|
||||
order = order,
|
||||
products = orderProductRepository.findByOrderId(orderId = order.id!!)
|
||||
.map { orderProduct -> orderProduct.productId }
|
||||
.let { productIds -> productRepository.findAllById(productIds).toList() }
|
||||
products = findProductsByOrderId(order.id!!),
|
||||
) } }
|
||||
|
||||
@Transactional
|
||||
fun createOrder(customer: Customer, products: Set<Product>): Order {
|
||||
val order = Order(
|
||||
id = null,
|
||||
guid = UUID.randomUUID(),
|
||||
guid = commonGenerator.generateUUID(),
|
||||
customerId = customer.id!!,
|
||||
deliveredAt = null,
|
||||
createdAt = OffsetDateTime.now(),
|
||||
createdAt = commonGenerator.generateCurrentTime(),
|
||||
updatedAt = null,
|
||||
)
|
||||
|
||||
return orderRepository.save(order)
|
||||
.also {
|
||||
savedOrder -> products.toList()
|
||||
.map { product -> OrderProduct(
|
||||
guid = UUID.randomUUID(),
|
||||
orderId = savedOrder.id!!,
|
||||
productId = product.id!!,
|
||||
createdAt = OffsetDateTime.now(),
|
||||
updatedAt = null
|
||||
) }
|
||||
.also { orderProductRepository.saveAll(it) }
|
||||
.also { saveProductsForNewOrder(it, products.toList()) }
|
||||
}
|
||||
|
||||
private fun findProductsByOrderId(orderId: Long): List<Product> =
|
||||
orderProductRepository.findByOrderId(orderId = orderId)
|
||||
.map { it.productId }
|
||||
.let {
|
||||
if (it.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
productRepository.findAllById(it).toList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveProductsForNewOrder(savedOrder: Order, products: List<Product>) {
|
||||
products.map {
|
||||
OrderProduct(
|
||||
guid = commonGenerator.generateUUID(),
|
||||
orderId = savedOrder.id!!,
|
||||
productId = it.id!!,
|
||||
createdAt = commonGenerator.generateCurrentTime(),
|
||||
updatedAt = null
|
||||
)
|
||||
}.also { orderProductRepository.saveAll(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.github.dannecron.demo.services.database.product
|
||||
|
||||
import com.github.dannecron.demo.models.Product
|
||||
import com.github.dannecron.demo.db.entity.Product
|
||||
import com.github.dannecron.demo.services.database.exceptions.AlreadyDeletedException
|
||||
import com.github.dannecron.demo.services.database.exceptions.ProductNotFoundException
|
||||
import com.github.dannecron.demo.services.kafka.exceptions.InvalidArgumentException
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
interface ProductService {
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
package com.github.dannecron.demo.services.database.product
|
||||
|
||||
import com.github.dannecron.demo.models.Product
|
||||
import com.github.dannecron.demo.providers.ProductRepository
|
||||
import com.github.dannecron.demo.core.services.generation.CommonGenerator
|
||||
import com.github.dannecron.demo.db.entity.Product
|
||||
import com.github.dannecron.demo.db.repository.ProductRepository
|
||||
import com.github.dannecron.demo.services.database.exceptions.AlreadyDeletedException
|
||||
import com.github.dannecron.demo.services.database.exceptions.ProductNotFoundException
|
||||
import com.github.dannecron.demo.services.kafka.Producer
|
||||
import com.github.dannecron.demo.services.kafka.dto.ProductDto
|
||||
import com.github.dannecron.demo.services.kafka.exceptions.InvalidArgumentException
|
||||
import com.github.dannecron.demo.utils.LoggerDelegate
|
||||
import net.logstash.logback.marker.Markers
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class ProductServiceImpl(
|
||||
private val defaultSyncTopic: String,
|
||||
private val productRepository: ProductRepository,
|
||||
private val producer: Producer,
|
||||
private val commonGenerator: CommonGenerator,
|
||||
): ProductService {
|
||||
private val logger by LoggerDelegate()
|
||||
|
||||
@@ -32,11 +37,11 @@ class ProductServiceImpl(
|
||||
override fun create(name: String, price: Long, description: String?): Product {
|
||||
val product = Product(
|
||||
id = null,
|
||||
guid = UUID.randomUUID(),
|
||||
guid = commonGenerator.generateUUID(),
|
||||
name = name,
|
||||
description = description,
|
||||
price = price,
|
||||
createdAt = OffsetDateTime.now(),
|
||||
createdAt = commonGenerator.generateCurrentTime(),
|
||||
updatedAt = null,
|
||||
deletedAt = null,
|
||||
)
|
||||
@@ -52,7 +57,7 @@ class ProductServiceImpl(
|
||||
}
|
||||
|
||||
val deletedProduct = product.copy(
|
||||
deletedAt = OffsetDateTime.now(),
|
||||
deletedAt = commonGenerator.generateCurrentTime(),
|
||||
)
|
||||
|
||||
return productRepository.save(deletedProduct)
|
||||
@@ -61,7 +66,17 @@ class ProductServiceImpl(
|
||||
override fun syncToKafka(guid: UUID, topic: String?) {
|
||||
val product = findByGuid(guid) ?: throw ProductNotFoundException()
|
||||
|
||||
producer.produceProductInfo(topic ?: defaultSyncTopic, product)
|
||||
producer.produceProductSync(product.toKafkaDto())
|
||||
}
|
||||
|
||||
private fun Product.toKafkaDto() = ProductDto(
|
||||
id = id ?: throw InvalidArgumentException("product.id"),
|
||||
guid = guid.toString(),
|
||||
name = name,
|
||||
description = description,
|
||||
price = price,
|
||||
createdAt = createdAt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
|
||||
updatedAt = updatedAt?.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
|
||||
deletedAt = deletedAt?.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.github.dannecron.demo.services.validation
|
||||
|
||||
import com.github.dannecron.demo.services.validation.exceptions.ElementNotValidException
|
||||
import com.github.dannecron.demo.services.validation.exceptions.SchemaNotFoundException
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
interface SchemaValidator {
|
||||
companion object {
|
||||
const val SCHEMA_KAFKA_PRODUCT_SYNC = "kafka-product-sync"
|
||||
}
|
||||
|
||||
@Throws(ElementNotValidException::class, SchemaNotFoundException::class)
|
||||
fun validate(schemaName: String, value: JsonElement)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.github.dannecron.demo.services.validation
|
||||
|
||||
import com.github.dannecron.demo.services.validation.exceptions.ElementNotValidException
|
||||
import com.github.dannecron.demo.services.validation.exceptions.SchemaNotFoundException
|
||||
import io.github.optimumcode.json.schema.JsonSchema
|
||||
import io.github.optimumcode.json.schema.ValidationError
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import org.springframework.util.ResourceUtils
|
||||
|
||||
class SchemaValidatorImp(
|
||||
private val schemaMap: Map<String, String>,
|
||||
): SchemaValidator {
|
||||
private val loadedSchema: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
override fun validate(schemaName: String, value: JsonElement) {
|
||||
JsonSchema.fromDefinition(
|
||||
getSchema(schemaName),
|
||||
).also {
|
||||
val errors = mutableListOf<ValidationError>()
|
||||
|
||||
if (!it.validate(value, errors::add)) {
|
||||
throw ElementNotValidException(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSchema(schemaName: String): String {
|
||||
val loaded = loadedSchema[schemaName]
|
||||
if (loaded != null) {
|
||||
return loaded
|
||||
}
|
||||
|
||||
val schemaFile = schemaMap[schemaName]
|
||||
?: throw SchemaNotFoundException()
|
||||
|
||||
val schema = ResourceUtils.getFile("classpath:json-schemas/$schemaFile")
|
||||
.readText(Charsets.UTF_8)
|
||||
loadedSchema[schemaName] = schema
|
||||
|
||||
return schema
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.github.dannecron.demo.services.validation.exceptions
|
||||
|
||||
import io.github.optimumcode.json.schema.ValidationError
|
||||
|
||||
class ElementNotValidException(
|
||||
val validationErrors: List<ValidationError>,
|
||||
): RuntimeException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.github.dannecron.demo.services.validation.exceptions
|
||||
|
||||
class SchemaNotFoundException: RuntimeException()
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.github.dannecron.demo.utils
|
||||
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun Double.roundTo(numFractionDigits: Int): Double {
|
||||
val factor = 10.0.pow(numFractionDigits.toDouble())
|
||||
return (this * factor).roundToInt() / factor
|
||||
}
|
||||
|
||||
fun String.snakeToCamelCase(): String {
|
||||
val pattern = "_[a-z]".toRegex()
|
||||
return replace(pattern) { it.value.last().uppercase() }
|
||||
}
|
||||
Reference in New Issue
Block a user