1.1.0 add service / repository / query spring auto config function
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.7.0'
|
||||
kotlin_version = '1.6.10'
|
||||
spring_version = "2.7.0"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ buildscript {
|
||||
|
||||
subprojects {
|
||||
group 'com.synebula'
|
||||
version '1.0.0'
|
||||
version '1.1.0'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
rootProject.name = 'gaea'
|
||||
include 'src:gaea'
|
||||
include 'src:gaea.app'
|
||||
include 'src:gaea.mongo'
|
||||
include 'src:gaea.mongodb'
|
||||
include 'src:gaea.spring'
|
||||
include 'src:gaea.spring'
|
||||
findProject(':src:gaea.spring')?.name = 'gaea.spring'
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ apply plugin: 'kotlin-spring'
|
||||
|
||||
dependencies {
|
||||
api project(":src:gaea")
|
||||
api project(":src:gaea.spring")
|
||||
|
||||
api("org.springframework.boot:spring-boot-starter-web:$spring_version")
|
||||
api("org.springframework.boot:spring-boot-starter-aop:$spring_version")
|
||||
api("org.springframework.boot:spring-boot-starter-mail:$spring_version")
|
||||
|
||||
@@ -13,16 +13,14 @@ import javax.annotation.Resource
|
||||
* 联合服务,同时实现了ICommandApp和IQueryApp接口
|
||||
*
|
||||
* @param name 业务名称
|
||||
* @param clazz 试图业务对象
|
||||
* @param service 业务domain服务
|
||||
* @param query 业务查询服务
|
||||
* @param logger 日志组件
|
||||
*/
|
||||
open class Application<TCommand : ICommand, TView, ID>(
|
||||
override var name: String,
|
||||
override var clazz: Class<TView>,
|
||||
override var service: IService<ID>,
|
||||
override var query: IQuery,
|
||||
override var query: IQuery<TView, ID>,
|
||||
override var logger: ILogger,
|
||||
) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> {
|
||||
|
||||
|
||||
@@ -13,16 +13,14 @@ import javax.annotation.Resource
|
||||
* 简单的服务, 取消了Command对象
|
||||
*
|
||||
* @param name 业务名称
|
||||
* @param clazz 业务对象类型
|
||||
* @param service 业务domain服务
|
||||
* @param query 业务查询服务
|
||||
* @param logger 日志组件
|
||||
*/
|
||||
open class SimpleApplication<TRoot : IAggregateRoot<ID>, ID>(
|
||||
override var name: String,
|
||||
override var clazz: Class<TRoot>,
|
||||
override var service: ISimpleService<TRoot, ID>,
|
||||
override var query: IQuery,
|
||||
override var query: IQuery<TRoot, ID>,
|
||||
override var logger: ILogger,
|
||||
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.synebula.gaea.app.autoconfig.service
|
||||
|
||||
import com.synebula.gaea.spring.autoconfig.Factory
|
||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
|
||||
class ServiceFactory(
|
||||
supertype: Class<*>,
|
||||
var beanFactory: BeanFactory,
|
||||
var implementBeanNames: Array<String> = arrayOf()
|
||||
) : Factory(supertype) {
|
||||
override fun createProxy(): Proxy {
|
||||
return ServiceProxy(supertype, this.beanFactory, this.implementBeanNames)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.synebula.gaea.app.autoconfig.service
|
||||
|
||||
import com.synebula.gaea.data.serialization.IObjectMapper
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.domain.service.IService
|
||||
import com.synebula.gaea.domain.service.Service
|
||||
import com.synebula.gaea.domain.service.ServiceDependency
|
||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
import java.io.InvalidClassException
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class ServiceProxy(
|
||||
private var supertype: Class<*>, private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf()
|
||||
) : Proxy() {
|
||||
|
||||
private var service: IService<*>
|
||||
|
||||
init {
|
||||
// 如果没有实现类, 使用Service类代理
|
||||
if (implementBeanNames.isEmpty()) {
|
||||
// 如果没有实现类并且没有ServiceDependency注解, 则抛出异常
|
||||
if (!this.supertype.declaredAnnotations.any { it.annotationClass == ServiceDependency::class }) {
|
||||
throw InvalidClassException(
|
||||
"interface ${this.supertype.name} must has implementation class or annotation by ${ServiceDependency::class.qualifiedName}"
|
||||
)
|
||||
}
|
||||
val serviceDependency = this.supertype.getDeclaredAnnotation(ServiceDependency::class.java)
|
||||
val repo = this.beanFactory.getBean(serviceDependency.repo.java)
|
||||
val mapper = this.beanFactory.getBean(IObjectMapper::class.java)
|
||||
val constructor = Service::class.java.getConstructor(
|
||||
Class::class.java, IRepository::class.java, IObjectMapper::class.java
|
||||
)
|
||||
this.service = constructor.newInstance(serviceDependency.clazz.java, repo, mapper)
|
||||
} else {
|
||||
this.service = this.beanFactory.getBean(implementBeanNames[0]) as IService<*>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行代理方法
|
||||
*
|
||||
* @param proxy 代理对象
|
||||
* @param method 需要执行的方法
|
||||
* @param args 参数列表
|
||||
* @return 方法执行结果
|
||||
*/
|
||||
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
try {
|
||||
val proxyMethod = this.service.javaClass.getDeclaredMethod(method.name, *method.parameterTypes)
|
||||
return proxyMethod.invoke(this.service, *args)
|
||||
} catch (ex: NoSuchMethodException) {
|
||||
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.service::class.java}], you must implements interface [${this.supertype.name}] ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.synebula.gaea.app.autoconfig.service
|
||||
|
||||
import com.synebula.gaea.domain.service.IService
|
||||
import com.synebula.gaea.spring.autoconfig.Register
|
||||
import org.springframework.beans.factory.config.BeanDefinition
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition
|
||||
import org.springframework.core.annotation.AnnotationAttributes
|
||||
import org.springframework.core.type.AnnotationMetadata
|
||||
|
||||
class ServiceRegister : Register() {
|
||||
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
|
||||
val result = mutableMapOf<String, BeanDefinition>()
|
||||
|
||||
// 获取注解参数信息:basePackages
|
||||
val attributes = AnnotationAttributes(
|
||||
metadata.getAnnotationAttributes(
|
||||
ServiceScan::class.java.name
|
||||
) ?: mapOf()
|
||||
)
|
||||
val basePackages = attributes.getStringArray("basePackages")
|
||||
val beanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(IService::class.java))))
|
||||
beanDefinitions.forEach { beanDefinition ->
|
||||
// 获取实际的bean类型
|
||||
val beanClazz: Class<*> = try {
|
||||
Class.forName(beanDefinition.beanClassName)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
throw e
|
||||
}
|
||||
|
||||
// 尝试获取实际继承类型
|
||||
val implBeanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(beanClazz))))
|
||||
implBeanDefinitions.forEach {
|
||||
it.isAutowireCandidate = false
|
||||
result[it.beanClassName!!] = it
|
||||
}
|
||||
|
||||
// 构造BeanDefinition
|
||||
val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz)
|
||||
builder.addConstructorArgValue(beanClazz)
|
||||
builder.addConstructorArgValue(this._beanFactory)
|
||||
builder.addConstructorArgValue(implBeanDefinitions.map { it.beanClassName })
|
||||
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
||||
definition.beanClass = ServiceFactory::class.java
|
||||
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
||||
result[beanClazz.name] = definition
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.synebula.gaea.app.autoconfig.service
|
||||
|
||||
import org.springframework.context.annotation.Import
|
||||
import java.lang.annotation.Inherited
|
||||
|
||||
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
@Inherited
|
||||
@Import(ServiceRegister::class)
|
||||
annotation class ServiceScan(val basePackages: Array<String> = [])
|
||||
@@ -13,17 +13,12 @@ interface IQueryApp<TView, ID> : IApplication {
|
||||
/**
|
||||
* 查询服务
|
||||
*/
|
||||
var query: IQuery
|
||||
|
||||
/**
|
||||
* 查询的View类型
|
||||
*/
|
||||
var clazz: Class<TView>
|
||||
var query: IQuery<TView, ID>
|
||||
|
||||
@Method("获取数据")
|
||||
@GetMapping("/{id:.+}")
|
||||
fun get(@PathVariable id: ID): HttpMessage {
|
||||
val data = this.query.get(id, clazz)
|
||||
val data = this.query.get(id)
|
||||
val msg = HttpMessage()
|
||||
msg.data = data
|
||||
return msg
|
||||
@@ -32,19 +27,19 @@ interface IQueryApp<TView, ID> : IApplication {
|
||||
@Method("获取列表数据")
|
||||
@GetMapping
|
||||
fun list(@RequestParam params: LinkedHashMap<String, Any>): HttpMessage {
|
||||
val data = this.query.list(params, clazz)
|
||||
val data = this.query.list(params)
|
||||
return HttpMessage(data)
|
||||
}
|
||||
|
||||
@Method("获取分页数据")
|
||||
@GetMapping("/segments/{size}/pages/{page}")
|
||||
@GetMapping("/size/{size}/pages/{page}")
|
||||
fun paging(
|
||||
@PathVariable size: Int,
|
||||
@PathVariable page: Int,
|
||||
@RequestParam parameters: LinkedHashMap<String, Any>
|
||||
): HttpMessage {
|
||||
val params = Params(page, size, parameters)
|
||||
val data = this.query.paging(params, clazz)
|
||||
val data = this.query.paging(params)
|
||||
return HttpMessage(data)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import com.synebula.gaea.query.IQuery
|
||||
*/
|
||||
open class QueryApp<TView, ID>(
|
||||
override var name: String,
|
||||
override var clazz: Class<TView>,
|
||||
override var query: IQuery,
|
||||
override var query: IQuery<TView, ID>,
|
||||
override var logger: ILogger,
|
||||
) : IQueryApp<TView, ID>
|
||||
@@ -1,5 +1,6 @@
|
||||
dependencies {
|
||||
api project(":src:gaea")
|
||||
api project(":src:gaea.spring")
|
||||
api("org.springframework.boot:spring-boot-starter-data-mongodb:$spring_version")
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.synebula.gaea.mongo
|
||||
package com.synebula.gaea.mongodb
|
||||
|
||||
import com.synebula.gaea.data.date.DateTime
|
||||
import com.synebula.gaea.query.annotation.Where
|
||||
import com.synebula.gaea.query.type.Operator
|
||||
import com.synebula.gaea.query.type.Order
|
||||
import com.synebula.gaea.query.Operator
|
||||
import com.synebula.gaea.query.Order
|
||||
import com.synebula.gaea.query.Where
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.data.mongodb.core.query.Criteria
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.synebula.gaea.mongodb.autoconfig
|
||||
|
||||
import com.synebula.gaea.spring.autoconfig.Factory
|
||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
|
||||
class MongodbRepoFactory(
|
||||
supertype: Class<*>,
|
||||
var beanFactory: BeanFactory,
|
||||
var implementBeanNames: Array<String> = arrayOf()
|
||||
) : Factory(supertype) {
|
||||
override fun createProxy(): Proxy {
|
||||
return MongodbRepoProxy(supertype, this.beanFactory, this.implementBeanNames)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.synebula.gaea.mongodb.autoconfig
|
||||
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.log.ILogger
|
||||
import com.synebula.gaea.mongodb.query.MongodbQuery
|
||||
import com.synebula.gaea.mongodb.repository.MongodbRepository
|
||||
import com.synebula.gaea.query.IQuery
|
||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import java.io.InvalidClassException
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
||||
class MongodbRepoProxy(
|
||||
private var supertype: Class<*>, private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf()
|
||||
) : Proxy() {
|
||||
|
||||
private var repo: IRepository<*, *>? = null
|
||||
|
||||
private var query: IQuery<*, *>? = null
|
||||
|
||||
init {
|
||||
if (this.supertype.interfaces.any { it == IRepository::class.java }) {
|
||||
// 如果是IRepository子接口
|
||||
if (implementBeanNames.isEmpty()) {
|
||||
val genericInterfaces = this.supertype.genericInterfaces.find {
|
||||
it.typeName.startsWith(IRepository::class.java.typeName)
|
||||
}!!
|
||||
val constructor = MongodbRepository::class.java.getConstructor(
|
||||
Class::class.java, MongoTemplate::class.java
|
||||
)
|
||||
this.repo = constructor.newInstance(
|
||||
(genericInterfaces as ParameterizedType).actualTypeArguments[0],
|
||||
this.beanFactory.getBean(MongoTemplate::class.java)
|
||||
)
|
||||
} else {
|
||||
this.repo = this.beanFactory.getBean(implementBeanNames[0]) as IRepository<*, *>
|
||||
}
|
||||
} else {
|
||||
// 否则是IQuery子接口
|
||||
if (implementBeanNames.isEmpty()) {
|
||||
val genericInterfaces = this.supertype.genericInterfaces.find {
|
||||
it.typeName.startsWith(IQuery::class.java.typeName)
|
||||
}!!
|
||||
val constructor = MongodbQuery::class.java.getConstructor(
|
||||
Class::class.java, MongoTemplate::class.java, ILogger::class.java
|
||||
)
|
||||
this.query = constructor.newInstance(
|
||||
(genericInterfaces as ParameterizedType).actualTypeArguments[0],
|
||||
this.beanFactory.getBean(MongoTemplate::class.java),
|
||||
this.beanFactory.getBean(ILogger::class.java),
|
||||
)
|
||||
} else {
|
||||
this.query = this.beanFactory.getBean(implementBeanNames[0]) as IQuery<*, *>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行代理方法
|
||||
*
|
||||
* @param proxy 代理对象
|
||||
* @param method 需要执行的方法
|
||||
* @param args 参数列表
|
||||
* @return 方法执行结果
|
||||
*/
|
||||
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
val proxyClazz = if (this.repo != null) {
|
||||
this.repo!!.javaClass
|
||||
} else if (this.query != null) {
|
||||
this.query!!.javaClass
|
||||
} else
|
||||
throw InvalidClassException("class ${this.supertype.name} property repo and query are both null")
|
||||
|
||||
try {
|
||||
val proxyMethod: Method = proxyClazz.getDeclaredMethod(method.name, *method.parameterTypes)
|
||||
return proxyMethod.invoke(this.repo, *args)
|
||||
} catch (ex: NoSuchMethodException) {
|
||||
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${proxyClazz}], you must implements interface [${this.supertype.name}] ")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.synebula.gaea.mongodb.autoconfig
|
||||
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.query.IQuery
|
||||
import com.synebula.gaea.spring.autoconfig.Register
|
||||
import org.springframework.beans.factory.config.BeanDefinition
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition
|
||||
import org.springframework.core.annotation.AnnotationAttributes
|
||||
import org.springframework.core.type.AnnotationMetadata
|
||||
|
||||
class MongodbRepoRegister : Register() {
|
||||
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
|
||||
val result = mutableMapOf<String, BeanDefinition>()
|
||||
|
||||
// 获取注解参数信息:basePackages
|
||||
val attributes = AnnotationAttributes(
|
||||
metadata.getAnnotationAttributes(
|
||||
MongodbRepoScan::class.java.name
|
||||
) ?: mapOf()
|
||||
)
|
||||
val basePackages = attributes.getStringArray("basePackages")
|
||||
val beanDefinitions = this.doScan(
|
||||
basePackages,
|
||||
arrayOf(this.interfaceFilter(arrayOf(IRepository::class.java, IQuery::class.java)))
|
||||
)
|
||||
beanDefinitions.forEach { beanDefinition ->
|
||||
// 获取实际的bean类型
|
||||
val beanClazz: Class<*> = try {
|
||||
Class.forName(beanDefinition.beanClassName)
|
||||
} catch (ex: ClassNotFoundException) {
|
||||
throw ex
|
||||
}
|
||||
|
||||
// 尝试获取实际继承类型
|
||||
val implBeanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(beanClazz))))
|
||||
implBeanDefinitions.forEach {
|
||||
it.isAutowireCandidate = false
|
||||
result[it.beanClassName!!] = it
|
||||
}
|
||||
|
||||
// 构造BeanDefinition
|
||||
val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz)
|
||||
builder.addConstructorArgValue(beanClazz)
|
||||
builder.addConstructorArgValue(this._beanFactory)
|
||||
builder.addConstructorArgValue(implBeanDefinitions.map { it.beanClassName })
|
||||
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
||||
definition.beanClass = MongodbRepoFactory::class.java
|
||||
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
||||
result[beanClazz.name] = definition
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.synebula.gaea.mongodb.autoconfig
|
||||
|
||||
import org.springframework.context.annotation.Import
|
||||
import java.lang.annotation.Inherited
|
||||
|
||||
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
@Inherited
|
||||
@Import(MongodbRepoRegister::class)
|
||||
annotation class MongodbRepoScan(val basePackages: Array<String> = [])
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.synebula.gaea.mongodb.query
|
||||
|
||||
import com.synebula.gaea.ext.fieldNames
|
||||
import com.synebula.gaea.ext.firstCharLowerCase
|
||||
import com.synebula.gaea.log.ILogger
|
||||
import com.synebula.gaea.mongodb.order
|
||||
import com.synebula.gaea.mongodb.select
|
||||
import com.synebula.gaea.mongodb.where
|
||||
import com.synebula.gaea.mongodb.whereId
|
||||
import com.synebula.gaea.query.IQuery
|
||||
import com.synebula.gaea.query.Page
|
||||
import com.synebula.gaea.query.Params
|
||||
import com.synebula.gaea.query.Table
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.query.Criteria
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
|
||||
/**
|
||||
* 实现IQuery的Mongodb查询类
|
||||
* @param template MongodbRepo对象
|
||||
*/
|
||||
|
||||
open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var template: MongoTemplate, var logger: ILogger) :
|
||||
IQuery<TView, ID> {
|
||||
|
||||
/**
|
||||
* 使用View解析是collection时是否校验存在,默认不校验
|
||||
*/
|
||||
var validViewCollection = false
|
||||
|
||||
override fun get(id: ID): TView? {
|
||||
return this.template.findOne(whereId(id), clazz, this.collection(clazz))
|
||||
}
|
||||
|
||||
override fun list(params: Map<String, Any>?): List<TView> {
|
||||
val fields = this.fields(clazz)
|
||||
val query = Query()
|
||||
query.where(params, clazz)
|
||||
query.select(fields)
|
||||
return this.find(query, clazz)
|
||||
}
|
||||
|
||||
override fun count(params: Map<String, Any>?): Int {
|
||||
val query = Query()
|
||||
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt()
|
||||
}
|
||||
|
||||
override fun paging(params: Params): Page<TView> {
|
||||
val query = Query()
|
||||
val fields = this.fields(clazz)
|
||||
val result = Page<TView>(params.page, params.size)
|
||||
result.total = this.count(params.parameters)
|
||||
//如果总数和索引相同,说明该页没有数据,直接跳到上一页
|
||||
if (result.total == result.index) {
|
||||
params.page -= 1
|
||||
result.page -= 1
|
||||
}
|
||||
query.select(fields)
|
||||
query.where(params.parameters, clazz)
|
||||
query.with(order(params.orders))
|
||||
query.skip(params.index).limit(params.size)
|
||||
result.data = this.find(query, clazz)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun range(field: String, params: List<Any>): List<TView> {
|
||||
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
|
||||
}
|
||||
|
||||
protected fun find(query: Query, clazz: Class<TView>): List<TView> {
|
||||
return this.template.find(query, clazz, this.collection(clazz))
|
||||
}
|
||||
|
||||
protected fun fields(clazz: Class<TView>): Array<String> {
|
||||
val fields = mutableListOf<String>()
|
||||
fields.addAll(clazz.fieldNames())
|
||||
var parent = clazz.superclass
|
||||
while (parent != Any::class.java) {
|
||||
fields.addAll(clazz.superclass.fieldNames())
|
||||
parent = parent.superclass
|
||||
}
|
||||
return fields.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取collection
|
||||
*/
|
||||
protected fun collection(clazz: Class<TView>): String {
|
||||
val table: Table? = clazz.getDeclaredAnnotation(
|
||||
Table::class.java
|
||||
)
|
||||
return if (table != null) return table.name
|
||||
else {
|
||||
this.logger.info(this, "视图类没有标记[Collection]注解,无法获取Collection名称。尝试使用View<${clazz.name}>名称解析集合")
|
||||
val name = clazz.simpleName.removeSuffix("View").firstCharLowerCase()
|
||||
if (!validViewCollection || this.template.collectionExists(name)) name
|
||||
else {
|
||||
throw RuntimeException("找不到名为[${clazz.name}]的集合")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package com.synebula.gaea.mongo.query
|
||||
package com.synebula.gaea.mongodb.query
|
||||
|
||||
|
||||
import com.synebula.gaea.ext.fieldNames
|
||||
import com.synebula.gaea.ext.firstCharLowerCase
|
||||
import com.synebula.gaea.log.ILogger
|
||||
import com.synebula.gaea.mongo.order
|
||||
import com.synebula.gaea.mongo.select
|
||||
import com.synebula.gaea.mongo.where
|
||||
import com.synebula.gaea.mongo.whereId
|
||||
import com.synebula.gaea.query.IQuery
|
||||
import com.synebula.gaea.mongodb.order
|
||||
import com.synebula.gaea.mongodb.select
|
||||
import com.synebula.gaea.mongodb.where
|
||||
import com.synebula.gaea.mongodb.whereId
|
||||
import com.synebula.gaea.query.IUniversalQuery
|
||||
import com.synebula.gaea.query.Page
|
||||
import com.synebula.gaea.query.Params
|
||||
import com.synebula.gaea.query.annotation.Table
|
||||
import com.synebula.gaea.query.Table
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.query.Criteria
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
@@ -19,8 +20,7 @@ import org.springframework.data.mongodb.core.query.Query
|
||||
* 实现IQuery的Mongodb查询类
|
||||
* @param template MongodbRepo对象
|
||||
*/
|
||||
|
||||
open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQuery {
|
||||
open class MongodbUniversalQuery(var template: MongoTemplate, var logger: ILogger) : IUniversalQuery {
|
||||
|
||||
/**
|
||||
* 使用View解析是collection时是否校验存在,默认不校验
|
||||
@@ -36,7 +36,7 @@ open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQue
|
||||
val query = Query()
|
||||
query.where(params, clazz)
|
||||
query.select(fields)
|
||||
return this.template.find(query, clazz, this.collection(clazz))
|
||||
return this.find(query, clazz)
|
||||
}
|
||||
|
||||
override fun <TView> count(params: Map<String, Any>?, clazz: Class<TView>): Int {
|
||||
@@ -58,12 +58,16 @@ open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQue
|
||||
query.where(params.parameters, clazz)
|
||||
query.with(order(params.orders))
|
||||
query.skip(params.index).limit(params.size)
|
||||
result.data = this.template.find(query, clazz, this.collection(clazz))
|
||||
result.data = this.find(query, clazz)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
|
||||
return this.template.find(Query.query(Criteria.where(field).`in`(params)), clazz, this.collection(clazz))
|
||||
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
|
||||
}
|
||||
|
||||
protected fun <TView> find(query: Query, clazz: Class<TView>): List<TView> {
|
||||
return this.template.find(query, clazz, this.collection(clazz))
|
||||
}
|
||||
|
||||
fun <TView> fields(clazz: Class<TView>): Array<String> {
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.synebula.gaea.mongodb.repository
|
||||
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.mongodb.where
|
||||
import com.synebula.gaea.mongodb.whereId
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
|
||||
/**
|
||||
* 实现[IRepository]的Mongodb仓储类
|
||||
* @param repo MongodbRepo对象
|
||||
*/
|
||||
open class MongodbRepository<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
||||
override var clazz: Class<TAggregateRoot>,
|
||||
protected var repo: MongoTemplate
|
||||
) : IRepository<TAggregateRoot, ID> {
|
||||
|
||||
override fun add(obj: TAggregateRoot) {
|
||||
this.repo.save(obj)
|
||||
}
|
||||
|
||||
override fun add(list: List<TAggregateRoot>) {
|
||||
this.repo.insert(list, clazz)
|
||||
}
|
||||
|
||||
override fun remove(id: ID) {
|
||||
this.repo.remove(whereId(id), clazz)
|
||||
}
|
||||
|
||||
override fun get(id: ID): TAggregateRoot? {
|
||||
return this.repo.findOne(whereId(id), clazz)
|
||||
}
|
||||
|
||||
override fun update(obj: TAggregateRoot) {
|
||||
this.repo.save(obj)
|
||||
}
|
||||
|
||||
override fun update(list: List<TAggregateRoot>) {
|
||||
this.repo.save(list)
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot> count(params: Map<String, Any>?): Int {
|
||||
val query = Query()
|
||||
return this.repo.count(query.where(params, clazz), clazz).toInt()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.synebula.gaea.mongo.repository
|
||||
package com.synebula.gaea.mongodb.repository
|
||||
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.mongo.where
|
||||
import com.synebula.gaea.mongo.whereId
|
||||
import com.synebula.gaea.domain.repository.IUniversalRepository
|
||||
import com.synebula.gaea.mongodb.where
|
||||
import com.synebula.gaea.mongodb.whereId
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.query.Query
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.springframework.data.mongodb.core.query.Query
|
||||
* 实现ITypedRepository的Mongodb仓储类
|
||||
* @param repo MongodbRepo对象
|
||||
*/
|
||||
open class MongodbRepository(private var repo: MongoTemplate) : IRepository {
|
||||
open class MongodbUniversalRepository(private var repo: MongoTemplate) : IUniversalRepository {
|
||||
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>) {
|
||||
this.repo.remove(whereId(id), clazz)
|
||||
@@ -25,21 +25,33 @@ open class MongodbRepository(private var repo: MongoTemplate) : IRepository {
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
|
||||
obj: TAggregateRoot,
|
||||
root: TAggregateRoot,
|
||||
clazz: Class<TAggregateRoot>,
|
||||
) {
|
||||
this.repo.save(obj)
|
||||
this.repo.save(root)
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: TAggregateRoot, clazz: Class<TAggregateRoot>) {
|
||||
this.repo.save(obj)
|
||||
/**
|
||||
* 更新多个个对象。
|
||||
*
|
||||
* @param roots 需要更新的对象。
|
||||
*/
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
|
||||
roots: List<TAggregateRoot>,
|
||||
clazz: Class<TAggregateRoot>
|
||||
) {
|
||||
this.repo.save(roots)
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>) {
|
||||
this.repo.save(root)
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(
|
||||
obj: List<TAggregateRoot>,
|
||||
roots: List<TAggregateRoot>,
|
||||
clazz: Class<TAggregateRoot>,
|
||||
) {
|
||||
this.repo.insert(obj, clazz)
|
||||
this.repo.insert(roots, clazz)
|
||||
}
|
||||
|
||||
override fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int {
|
||||
22
src/gaea.spring/build.gradle
Normal file
22
src/gaea.spring/build.gradle
Normal file
@@ -0,0 +1,22 @@
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlin_version")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-spring'
|
||||
|
||||
dependencies {
|
||||
implementation project(":src:gaea")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web:$spring_version")
|
||||
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
publish(MavenPublication) {
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.synebula.gaea.spring.autoconfig
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean
|
||||
import org.springframework.cglib.proxy.Enhancer
|
||||
import java.lang.reflect.Proxy as JdkProxy
|
||||
|
||||
/**
|
||||
* 代理生成工厂
|
||||
*
|
||||
* @param supertype 需要被代理的父类型
|
||||
* @param proxyType 代理类型:JDK 或 CGLIB
|
||||
*/
|
||||
abstract class Factory(
|
||||
protected val supertype: Class<*>,
|
||||
protected val proxyType: ProxyType = ProxyType.Cglib
|
||||
) : FactoryBean<Any> {
|
||||
override fun getObject(): Any {
|
||||
val handler: Proxy = this.createProxy()
|
||||
|
||||
//JDK 方式代理代码, 暂时选用cglib
|
||||
val proxy: Any = if (proxyType == ProxyType.JDK) {
|
||||
JdkProxy.newProxyInstance(
|
||||
this.supertype.classLoader, arrayOf(this.supertype), handler
|
||||
)
|
||||
} else { //cglib代理
|
||||
val enhancer = Enhancer()
|
||||
enhancer.setSuperclass(supertype)
|
||||
enhancer.setCallback(handler)
|
||||
enhancer.create()
|
||||
}
|
||||
|
||||
return proxy
|
||||
}
|
||||
|
||||
override fun getObjectType(): Class<*> {
|
||||
return supertype
|
||||
}
|
||||
|
||||
override fun isSingleton(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
abstract fun createProxy(): Proxy
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.synebula.gaea.spring.autoconfig
|
||||
|
||||
import org.springframework.cglib.proxy.MethodInterceptor
|
||||
import org.springframework.cglib.proxy.MethodProxy
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
|
||||
abstract class Proxy : MethodInterceptor, InvocationHandler {
|
||||
|
||||
/**
|
||||
* JDK 方式代理代码
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
return if (Any::class.java == method.declaringClass) {
|
||||
method.invoke(this, *args)
|
||||
} else {
|
||||
exec(proxy, method, args)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂时选用cglib 方式代理代码
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
override fun intercept(proxy: Any, method: Method, args: Array<Any>, methodProxy: MethodProxy): Any? {
|
||||
return if (Any::class.java == method.declaringClass) {
|
||||
methodProxy.invoke(this, args)
|
||||
} else {
|
||||
exec(proxy, method, args)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行代理方法
|
||||
*
|
||||
* @param proxy 代理对象
|
||||
* @param method 需要执行的方法
|
||||
* @param args 参数列表
|
||||
* @return 方法执行结果
|
||||
*/
|
||||
abstract fun exec(proxy: Any, method: Method, args: Array<Any>): Any?
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.synebula.gaea.spring.autoconfig
|
||||
|
||||
enum class ProxyType { JDK, Cglib }
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.synebula.gaea.spring.autoconfig
|
||||
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
import org.springframework.beans.factory.BeanFactoryAware
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
|
||||
import org.springframework.beans.factory.config.BeanDefinition
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
import org.springframework.context.EnvironmentAware
|
||||
import org.springframework.context.ResourceLoaderAware
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar
|
||||
import org.springframework.core.env.Environment
|
||||
import org.springframework.core.io.ResourceLoader
|
||||
import org.springframework.core.type.AnnotationMetadata
|
||||
import org.springframework.core.type.classreading.MetadataReader
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory
|
||||
import org.springframework.core.type.filter.TypeFilter
|
||||
import org.springframework.util.ClassUtils
|
||||
import java.util.*
|
||||
|
||||
abstract class Register : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
|
||||
EnvironmentAware, BeanFactoryAware {
|
||||
|
||||
protected var _classLoader: ClassLoader? = null
|
||||
protected var _environment: Environment? = null
|
||||
protected var _resourceLoader: ResourceLoader? = null
|
||||
protected var _beanFactory: BeanFactory? = null
|
||||
|
||||
override fun registerBeanDefinitions(metadata: AnnotationMetadata, registry: BeanDefinitionRegistry) {
|
||||
val beanDefinitions = this.scan(metadata)
|
||||
beanDefinitions.forEach { registry.registerBeanDefinition(it.key, it.value) }
|
||||
}
|
||||
|
||||
abstract fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition>
|
||||
|
||||
/**
|
||||
* 根据过滤器扫描直接包下bean
|
||||
*
|
||||
* @param packages 指定的扫描包
|
||||
* @param filters 过滤器
|
||||
* @return 扫描后的bean定义
|
||||
*/
|
||||
protected fun doScan(packages: Array<String>?, filters: Array<TypeFilter>): List<BeanDefinition> {
|
||||
val scanner: ClassPathScanningCandidateComponentProvider =
|
||||
object : ClassPathScanningCandidateComponentProvider() {
|
||||
override fun isCandidateComponent(beanDefinition: AnnotatedBeanDefinition): Boolean {
|
||||
try {
|
||||
val metadata = beanDefinition.metadata
|
||||
val target = ClassUtils.forName(metadata.className, _classLoader)
|
||||
return !target.isAnnotation
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
scanner.environment = _environment!!
|
||||
scanner.resourceLoader = _resourceLoader!!
|
||||
for (filter in filters) {
|
||||
scanner.addIncludeFilter(filter)
|
||||
}
|
||||
val beanDefinitions: MutableList<BeanDefinition> = LinkedList()
|
||||
for (basePackage in packages!!) {
|
||||
beanDefinitions.addAll(scanner.findCandidateComponents(basePackage))
|
||||
}
|
||||
return beanDefinitions
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定接口的类型过滤器
|
||||
*
|
||||
* @param interfaces 需要过滤的父接口类型
|
||||
* @param onlyInterface 是否只获取接口类型
|
||||
* @return 类型过滤器
|
||||
*/
|
||||
protected fun interfaceFilter(interfaces: Array<Class<*>>, onlyInterface: Boolean = false): TypeFilter {
|
||||
return TypeFilter { metadataReader: MetadataReader, _: MetadataReaderFactory? ->
|
||||
// 如果只获取接口类型且当前类型非接口 直接返回
|
||||
if (onlyInterface && !metadataReader.annotationMetadata.isInterface)
|
||||
return@TypeFilter false
|
||||
|
||||
var matched = false
|
||||
val interfaceNames = metadataReader.classMetadata.interfaceNames
|
||||
// 如果当前类型继承接口有任一需要过滤的接口则说明复合条件
|
||||
for (interfaceName in interfaceNames) {
|
||||
matched = interfaces.any { clazz -> clazz.name == interfaceName }
|
||||
}
|
||||
matched
|
||||
}
|
||||
}
|
||||
|
||||
override fun setResourceLoader(resourceLoader: ResourceLoader) {
|
||||
this._resourceLoader = resourceLoader
|
||||
}
|
||||
|
||||
override fun setBeanClassLoader(classLoader: ClassLoader) {
|
||||
this._classLoader = classLoader
|
||||
}
|
||||
|
||||
override fun setEnvironment(environment: Environment) {
|
||||
this._environment = environment
|
||||
}
|
||||
|
||||
@Throws(BeansException::class)
|
||||
override fun setBeanFactory(beanFactory: BeanFactory) {
|
||||
this._beanFactory = beanFactory
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,29 @@ import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
* 定义了提供增删改的仓储接口。
|
||||
* 本接口泛型放置到方法上,并需要显式提供聚合根的class对象
|
||||
*/
|
||||
interface IRepository {
|
||||
interface IRepository<TAggregateRoot : IAggregateRoot<ID>, ID> {
|
||||
|
||||
/**
|
||||
* 仓储的对象类
|
||||
*/
|
||||
var clazz: Class<TAggregateRoot>
|
||||
|
||||
/**
|
||||
* 插入单个对象。
|
||||
*
|
||||
* @param obj 需要插入的对象。
|
||||
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
||||
fun add(obj: TAggregateRoot)
|
||||
|
||||
/**
|
||||
* 插入多个个对象。
|
||||
*
|
||||
* @param obj 需要插入的对象。
|
||||
* @param list 需要插入的对象。
|
||||
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
|
||||
fun add(list: List<TAggregateRoot>)
|
||||
|
||||
|
||||
/**
|
||||
* 更新对象。
|
||||
@@ -29,24 +36,30 @@ interface IRepository {
|
||||
* @param obj 需要更新的对象。
|
||||
* @return
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(obj: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
||||
fun update(obj: TAggregateRoot)
|
||||
|
||||
/**
|
||||
* 更新多个个对象。
|
||||
*
|
||||
* @param list 需要新的对象。
|
||||
*/
|
||||
fun update(list: List<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 通过id删除该条数据
|
||||
*
|
||||
* @param id id
|
||||
* @param clazz 操作数据的类型
|
||||
* @param id 对象ID。
|
||||
* @return
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>)
|
||||
fun remove(id: ID)
|
||||
|
||||
/**
|
||||
* 根据ID获取对象。
|
||||
*
|
||||
* @param id id
|
||||
* @param clazz 操作数据的类型
|
||||
* @return 聚合根
|
||||
* @param id 对象ID。
|
||||
* @return
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(id: ID, clazz: Class<TAggregateRoot>): TAggregateRoot?
|
||||
fun get(id: ID): TAggregateRoot?
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,5 +68,7 @@ interface IRepository {
|
||||
* @param params 查询条件。
|
||||
* @return int
|
||||
*/
|
||||
fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int
|
||||
fun <TAggregateRoot> count(params: Map<String, Any>?): Int
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.synebula.gaea.domain.repository
|
||||
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
|
||||
/**
|
||||
* 继承本接口表示对象为仓储类。
|
||||
* 定义了提供增删改的仓储接口。
|
||||
* 本接口泛型定义在类上,方法中不需要显式提供聚合根的class对象,class对象作为类的成员变量声明。
|
||||
*
|
||||
* @param TAggregateRoot 聚合根类型
|
||||
* @author alex
|
||||
*/
|
||||
interface ISpecificRepository<TAggregateRoot : IAggregateRoot<ID>, ID> {
|
||||
|
||||
/**
|
||||
* 仓储的对象类
|
||||
*/
|
||||
var clazz: Class<TAggregateRoot>?
|
||||
|
||||
/**
|
||||
* 插入单个对象。
|
||||
*
|
||||
* @param obj 需要插入的对象。
|
||||
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
||||
*/
|
||||
fun add(obj: TAggregateRoot)
|
||||
|
||||
/**
|
||||
* 更新对象。
|
||||
*
|
||||
* @param obj 需要更新的对象。
|
||||
* @return
|
||||
*/
|
||||
fun update(obj: TAggregateRoot)
|
||||
|
||||
/**
|
||||
* 通过id删除该条数据
|
||||
*
|
||||
* @param id 对象ID。
|
||||
* @return
|
||||
*/
|
||||
fun remove(id: ID)
|
||||
|
||||
/**
|
||||
* 根据ID获取对象。
|
||||
*
|
||||
* @param id 对象ID。
|
||||
* @return
|
||||
*/
|
||||
fun get(id: ID): TAggregateRoot
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件查询符合条件记录的数量
|
||||
*
|
||||
* @param params 查询条件。
|
||||
* @return int
|
||||
*/
|
||||
fun <TAggregateRoot> count(params: Map<String, Any>?): Int
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.synebula.gaea.domain.repository
|
||||
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
|
||||
/**
|
||||
* 定义了提供增删改的仓储接口。
|
||||
* 本接口泛型放置到方法上,并需要显式提供聚合根的class对象
|
||||
*/
|
||||
interface IUniversalRepository {
|
||||
/**
|
||||
* 插入单个对象。
|
||||
*
|
||||
* @param root 需要插入的对象。
|
||||
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 插入多个个对象。
|
||||
*
|
||||
* @param roots 需要插入的对象。
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 更新对象。
|
||||
*
|
||||
* @param root 需要更新的对象。
|
||||
* @return
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 更新多个个对象。
|
||||
*
|
||||
* @param roots 需要更新的对象。
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 通过id删除该条数据
|
||||
*
|
||||
* @param id id
|
||||
* @param clazz 操作数据的类型
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 根据ID获取对象。
|
||||
*
|
||||
* @param id id
|
||||
* @param clazz 操作数据的类型
|
||||
* @return 聚合根
|
||||
*/
|
||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(id: ID, clazz: Class<TAggregateRoot>): TAggregateRoot?
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件查询符合条件记录的数量
|
||||
*
|
||||
* @param params 查询条件。
|
||||
* @return int
|
||||
*/
|
||||
fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.synebula.gaea.domain.service
|
||||
|
||||
import com.synebula.gaea.data.message.DataMessage
|
||||
import com.synebula.gaea.data.message.StatusMessage
|
||||
import com.synebula.gaea.log.ILogger
|
||||
|
||||
|
||||
/**
|
||||
@@ -12,27 +10,39 @@ import com.synebula.gaea.log.ILogger
|
||||
* @since 2016年9月18日 下午2:23:15
|
||||
*/
|
||||
interface IService<ID> {
|
||||
/**
|
||||
* 日志组件。
|
||||
*/
|
||||
var logger: ILogger
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param command 增加对象命令
|
||||
*/
|
||||
fun add(command: ICommand): DataMessage<ID>
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param commands 增加对象命令列表
|
||||
*/
|
||||
fun add(commands: List<ICommand>)
|
||||
|
||||
/**
|
||||
* 更新对象
|
||||
*
|
||||
* @param id 对象ID
|
||||
* @param command 更新对象命令
|
||||
*/
|
||||
fun update(id: ID, command: ICommand)
|
||||
|
||||
/**
|
||||
* 批量更新对象
|
||||
*
|
||||
* @param commands 更新对象命令列表
|
||||
*/
|
||||
fun update(commands: List<ICommand>)
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
* @param id 对象ID
|
||||
*/
|
||||
fun remove(id: ID)
|
||||
|
||||
/**
|
||||
* 添加一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
* @param func 监听方法。
|
||||
*/
|
||||
fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage)
|
||||
|
||||
/**
|
||||
* 移除一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
*/
|
||||
fun removeBeforeRemoveListener(key: String)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.synebula.gaea.domain.service
|
||||
|
||||
import com.synebula.gaea.data.message.DataMessage
|
||||
import com.synebula.gaea.data.message.StatusMessage
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.log.ILogger
|
||||
|
||||
@@ -18,22 +17,38 @@ interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
|
||||
*/
|
||||
var logger: ILogger
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param root 增加对象命令
|
||||
*/
|
||||
fun add(root: TAggregateRoot): DataMessage<ID>
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param roots 增加对象命令列表
|
||||
*/
|
||||
fun add(roots: List<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 更新对象
|
||||
*
|
||||
* @param id 对象ID
|
||||
* @param root 更新对象命令
|
||||
*/
|
||||
fun update(id: ID, root: TAggregateRoot)
|
||||
|
||||
/**
|
||||
* 批量更新对象
|
||||
*
|
||||
* @param roots 更新对象命令列表
|
||||
*/
|
||||
fun update(roots: List<TAggregateRoot>)
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
* @param id 对象ID
|
||||
*/
|
||||
fun remove(id: ID)
|
||||
|
||||
/**
|
||||
* 添加一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
* @param func 监听方法。
|
||||
*/
|
||||
fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage)
|
||||
|
||||
/**
|
||||
* 移除一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
*/
|
||||
fun removeBeforeRemoveListener(key: String)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,80 @@
|
||||
package com.synebula.gaea.domain.service
|
||||
|
||||
import com.synebula.gaea.data.message.DataMessage
|
||||
import com.synebula.gaea.data.message.StatusMessage
|
||||
import com.synebula.gaea.data.serialization.IObjectMapper
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.log.ILogger
|
||||
|
||||
|
||||
/**
|
||||
* 依赖了IRepository仓储借口的服务实现类 Service
|
||||
* 该类依赖仓储接口 @see IRepository, 需要显式提供聚合根的class对象
|
||||
* 依赖了IRepository仓储借口的服务实现类 GenericsService
|
||||
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
|
||||
*
|
||||
* @param repository 仓储对象
|
||||
* @param clazz 聚合根类对象
|
||||
* @param deserializer 对象转换组件
|
||||
* @param logger 日志组件
|
||||
* @param repo 仓储对象
|
||||
* @param mapper 对象转换组件
|
||||
* @author alex
|
||||
* @version 0.1
|
||||
* @since 2020-05-17
|
||||
*/
|
||||
open class Service<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
||||
protected open var clazz: Class<TAggregateRoot>,
|
||||
protected open var repository: IRepository,
|
||||
protected open var deserializer: IObjectMapper,
|
||||
override var logger: ILogger,
|
||||
open class Service<TRoot : IAggregateRoot<ID>, ID>(
|
||||
protected open var clazz: Class<TRoot>,
|
||||
protected open var repo: IRepository<TRoot, ID>,
|
||||
protected open var mapper: IObjectMapper,
|
||||
) : IService<ID> {
|
||||
|
||||
/**
|
||||
* 删除对象前执行监听器。
|
||||
*/
|
||||
protected val beforeRemoveListeners = mutableMapOf<String, (id: ID) -> StatusMessage>()
|
||||
|
||||
/**
|
||||
* 添加一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
* @param func 监听方法。
|
||||
* 增加对象
|
||||
*
|
||||
* @param command 增加对象命令
|
||||
*/
|
||||
override fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage) {
|
||||
this.beforeRemoveListeners[key] = func
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
*/
|
||||
override fun removeBeforeRemoveListener(key: String) {
|
||||
this.beforeRemoveListeners.remove(key)
|
||||
}
|
||||
|
||||
override fun add(command: ICommand): DataMessage<ID> {
|
||||
val msg = DataMessage<ID>()
|
||||
val root = this.deserialize(command)
|
||||
this.repository.add(root, this.clazz)
|
||||
val root = this.map(command)
|
||||
this.repo.add(root)
|
||||
msg.data = root.id
|
||||
return msg
|
||||
}
|
||||
|
||||
override fun update(id: ID, command: ICommand) {
|
||||
val root = this.deserialize(command)
|
||||
root.id = id
|
||||
this.repository.update(root, this.clazz)
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param commands 增加对象命令列表
|
||||
*/
|
||||
override fun add(commands: List<ICommand>) {
|
||||
val roots = commands.map { this.map(it) }
|
||||
this.repo.add(roots)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新对象
|
||||
*
|
||||
* @param id 对象ID
|
||||
* @param command 更新对象命令
|
||||
*/
|
||||
override fun update(id: ID, command: ICommand) {
|
||||
val root = this.map(command)
|
||||
root.id = id
|
||||
this.repo.update(root)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新对象
|
||||
*
|
||||
* @param commands 更新对象命令列表
|
||||
*/
|
||||
override fun update(commands: List<ICommand>) {
|
||||
val roots = commands.map { this.map(it) }
|
||||
this.repo.update(roots)
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
* @param id 对象ID
|
||||
*/
|
||||
override fun remove(id: ID) {
|
||||
val functions = this.beforeRemoveListeners.values
|
||||
var msg: StatusMessage
|
||||
for (func in functions) {
|
||||
msg = func(id)
|
||||
if (!msg.success()) {
|
||||
throw IllegalStateException(msg.message)
|
||||
}
|
||||
}
|
||||
this.repository.remove(id, this.clazz)
|
||||
this.repo.remove(id)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,9 +83,9 @@ open class Service<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
||||
* @param command 需要转换的命令
|
||||
* @return 聚合根
|
||||
*/
|
||||
protected open fun deserialize(command: ICommand): TAggregateRoot {
|
||||
protected open fun map(command: ICommand): TRoot {
|
||||
try {
|
||||
return deserializer.deserialize(command, this.clazz)
|
||||
return mapper.deserialize(command, this.clazz)
|
||||
} catch (ex: Exception) {
|
||||
throw RuntimeException("command not match aggregate root", ex)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.synebula.gaea.domain.service
|
||||
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* 声明服务的依赖项,若服务没有实现类则可以根据依赖项自动组装服务。
|
||||
*
|
||||
* @param clazz 依赖的聚合根类型
|
||||
* @param repo 依赖的[IRepository]类型
|
||||
*/
|
||||
annotation class ServiceDependency(
|
||||
val clazz: KClass<out IAggregateRoot<*>>,
|
||||
val repo: KClass<out IRepository<*, *>>,
|
||||
)
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.synebula.gaea.domain.service
|
||||
|
||||
import com.synebula.gaea.data.message.DataMessage
|
||||
import com.synebula.gaea.data.message.StatusMessage
|
||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||
import com.synebula.gaea.domain.repository.IRepository
|
||||
import com.synebula.gaea.log.ILogger
|
||||
|
||||
|
||||
/**
|
||||
* 依赖了IRepository仓储借口的服务实现类 Service
|
||||
* 该类依赖仓储接口 @see IRepository, 需要显式提供聚合根的class对象
|
||||
* 依赖了IRepository仓储借口的服务实现类 GenericsService
|
||||
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
|
||||
*
|
||||
* @param repository 仓储对象
|
||||
* @param clazz 聚合根类对象
|
||||
@@ -20,53 +19,41 @@ import com.synebula.gaea.log.ILogger
|
||||
*/
|
||||
open class SimpleService<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
||||
protected open var clazz: Class<TAggregateRoot>,
|
||||
protected open var repository: IRepository,
|
||||
protected open var repository: IRepository<TAggregateRoot, ID>,
|
||||
override var logger: ILogger,
|
||||
) : ISimpleService<TAggregateRoot, ID> {
|
||||
|
||||
/**
|
||||
* 删除对象前执行监听器。
|
||||
*/
|
||||
protected val beforeRemoveListeners = mutableMapOf<String, (id: ID) -> StatusMessage>()
|
||||
|
||||
/**
|
||||
* 添加一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
* @param func 监听方法。
|
||||
*/
|
||||
override fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage) {
|
||||
this.beforeRemoveListeners[key] = func
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个删除对象前执行监听器。
|
||||
* @param key 监听器标志。
|
||||
*/
|
||||
override fun removeBeforeRemoveListener(key: String) {
|
||||
this.beforeRemoveListeners.remove(key)
|
||||
}
|
||||
|
||||
override fun add(root: TAggregateRoot): DataMessage<ID> {
|
||||
val msg = DataMessage<ID>()
|
||||
this.repository.add(root, this.clazz)
|
||||
this.repository.add(root)
|
||||
msg.data = root.id
|
||||
return msg
|
||||
}
|
||||
|
||||
override fun update(id: ID, root: TAggregateRoot) {
|
||||
root.id = id
|
||||
this.repository.update(root, this.clazz)
|
||||
this.repository.update(root)
|
||||
}
|
||||
|
||||
override fun remove(id: ID) {
|
||||
val functions = this.beforeRemoveListeners.values
|
||||
var msg: StatusMessage
|
||||
for (func in functions) {
|
||||
msg = func(id)
|
||||
if (!msg.success()) {
|
||||
throw IllegalStateException(msg.message)
|
||||
this.repository.remove(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加对象
|
||||
*
|
||||
* @param roots 增加对象命令列表
|
||||
*/
|
||||
override fun add(roots: List<TAggregateRoot>) {
|
||||
this.repository.add(roots)
|
||||
}
|
||||
this.repository.remove(id, this.clazz)
|
||||
|
||||
/**
|
||||
* 批量更新对象
|
||||
*
|
||||
* @param roots 更新对象命令列表
|
||||
*/
|
||||
override fun update(roots: List<TAggregateRoot>) {
|
||||
this.repository.update(roots)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,22 +5,27 @@ package com.synebula.gaea.query
|
||||
*
|
||||
* @author alex
|
||||
*/
|
||||
interface IQuery {
|
||||
interface IQuery<TView, ID> {
|
||||
/**
|
||||
* 仓储的视图类
|
||||
*/
|
||||
var clazz: Class<TView>
|
||||
|
||||
/**
|
||||
* 根据Key获取对象。
|
||||
*
|
||||
* @param id 对象Key。
|
||||
* @return 视图结果
|
||||
*/
|
||||
fun <TView, ID> get(id: ID, clazz: Class<TView>): TView?
|
||||
fun get(id: ID): TView?
|
||||
|
||||
/**
|
||||
* 根据实体类条件查询所有符合条件记录
|
||||
*
|
||||
*`
|
||||
* @param params 查询条件。
|
||||
* @return 视图列表
|
||||
*/
|
||||
fun <TView> list(params: Map<String, Any>?, clazz: Class<TView>): List<TView>
|
||||
fun list(params: Map<String, Any>?): List<TView>
|
||||
|
||||
/**
|
||||
* 根据条件查询符合条件记录的数量
|
||||
@@ -28,7 +33,7 @@ interface IQuery {
|
||||
* @param params 查询条件。
|
||||
* @return 数量
|
||||
*/
|
||||
fun <TView> count(params: Map<String, Any>?, clazz: Class<TView>): Int
|
||||
fun count(params: Map<String, Any>?): Int
|
||||
|
||||
/**
|
||||
* 根据实体类条件查询所有符合条件记录(分页查询)
|
||||
@@ -36,7 +41,7 @@ interface IQuery {
|
||||
* @param params 分页条件
|
||||
* @return 分页数据
|
||||
*/
|
||||
fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView>
|
||||
fun paging(params: Params): Page<TView>
|
||||
|
||||
/**
|
||||
* 查询条件范围内数据。
|
||||
@@ -45,5 +50,5 @@ interface IQuery {
|
||||
*
|
||||
* @return 视图列表
|
||||
*/
|
||||
fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView>
|
||||
fun range(field: String, params: List<Any>): List<TView>
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.synebula.gaea.query
|
||||
|
||||
/**
|
||||
* 查询基接口。
|
||||
* 本接口泛型定义在类上,方法中不需要显式提供聚合根的class对象,class对象作为类的成员变量声明。
|
||||
* 查询基接口, 其中方法都指定了查询的视图类型。
|
||||
*
|
||||
* @author alex
|
||||
*/
|
||||
interface ISpecificQuery<TView> {
|
||||
interface IUniversalQuery {
|
||||
/**
|
||||
* 根据Key获取对象。
|
||||
*
|
||||
* @param id 对象Key。
|
||||
* @return 视图结果
|
||||
*/
|
||||
fun <TView, ID> get(id: ID): TView?
|
||||
fun <TView, ID> get(id: ID, clazz: Class<TView>): TView?
|
||||
|
||||
/**
|
||||
* 根据实体类条件查询所有符合条件记录
|
||||
@@ -20,7 +20,7 @@ interface ISpecificQuery<TView> {
|
||||
* @param params 查询条件。
|
||||
* @return 视图列表
|
||||
*/
|
||||
fun <TView> list(params: Map<String, Any>?): List<TView>
|
||||
fun <TView> list(params: Map<String, Any>?, clazz: Class<TView>): List<TView>
|
||||
|
||||
/**
|
||||
* 根据条件查询符合条件记录的数量
|
||||
@@ -28,7 +28,7 @@ interface ISpecificQuery<TView> {
|
||||
* @param params 查询条件。
|
||||
* @return 数量
|
||||
*/
|
||||
fun <TView> count(params: Map<String, Any>?): Int
|
||||
fun <TView> count(params: Map<String, Any>?, clazz: Class<TView>): Int
|
||||
|
||||
/**
|
||||
* 根据实体类条件查询所有符合条件记录(分页查询)
|
||||
@@ -36,7 +36,7 @@ interface ISpecificQuery<TView> {
|
||||
* @param params 分页条件
|
||||
* @return 分页数据
|
||||
*/
|
||||
fun <TView> paging(params: Params): Page<TView>
|
||||
fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView>
|
||||
|
||||
/**
|
||||
* 查询条件范围内数据。
|
||||
@@ -45,5 +45,5 @@ interface ISpecificQuery<TView> {
|
||||
*
|
||||
* @return 视图列表
|
||||
*/
|
||||
fun <TView> range(field: String, params: List<Any>): List<TView>
|
||||
fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView>
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.synebula.gaea.query.type
|
||||
package com.synebula.gaea.query
|
||||
|
||||
enum class Operator {
|
||||
/**
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.synebula.gaea.query.type
|
||||
package com.synebula.gaea.query
|
||||
|
||||
/**
|
||||
* class OrderType
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.synebula.gaea.query
|
||||
|
||||
import com.synebula.gaea.query.type.Order
|
||||
|
||||
/**
|
||||
* class 分页参数信息
|
||||
*
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package com.synebula.gaea.query.annotation
|
||||
package com.synebula.gaea.query
|
||||
|
||||
annotation class Table(val name: String = "")
|
||||
@@ -1,6 +1,4 @@
|
||||
package com.synebula.gaea.query.annotation
|
||||
|
||||
import com.synebula.gaea.query.type.Operator
|
||||
package com.synebula.gaea.query
|
||||
|
||||
/**
|
||||
* 字段注解,规定字段的查询方式
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.synebula.gaea.reflect
|
||||
|
||||
import com.synebula.gaea.bus.SubscriberRegistry
|
||||
|
||||
object Types {
|
||||
/**
|
||||
* 获取类的所有父类型。
|
||||
@@ -9,15 +7,15 @@ object Types {
|
||||
fun supertypes(clazz: Class<*>): Set<Class<*>> {
|
||||
val supertypes = mutableSetOf<Class<*>>()
|
||||
supertypes.add(clazz)
|
||||
if (clazz.superclass != null)
|
||||
supertypes.addAll(SubscriberRegistry.flattenHierarchy(clazz.superclass))
|
||||
if (clazz.interfaces.isNotEmpty()) {
|
||||
supertypes.addAll(clazz.interfaces.map { SubscriberRegistry.flattenHierarchy(it) }.reduce { r, c ->
|
||||
supertypes.addAll(clazz.interfaces.map { supertypes(it) }.reduce { r, c ->
|
||||
val all = r.toMutableSet()
|
||||
all.addAll(c)
|
||||
all
|
||||
})
|
||||
}
|
||||
if (clazz.superclass != null)
|
||||
supertypes.addAll(supertypes(clazz.superclass))
|
||||
return supertypes
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user