From 8f52f7e442dfb6d9ba5d8cfc2b5e65913c5428bd Mon Sep 17 00:00:00 2001 From: Ruslan Ibragimov Date: Sun, 11 Aug 2024 14:52:09 +0300 Subject: [PATCH] Komok 1.0.4 --- .gitignore | 3 + .run/Komok.run.xml | 10 +++ .../io/heapy/komok/tech/di/ez/BinderTest.kt | 20 ++--- .../tech/di/ez/EntryPointReturningTest.kt | 12 +-- .../heapy/komok/tech/di/ez/EntryPointTest.kt | 18 ++-- .../io/heapy/komok/tech/di/test2/ModuleA.kt | 12 +++ .../io/heapy/komok/tech/di/test2/ModuleB.kt | 18 ++++ .../io/heapy/komok/tech/di/test2/ModuleC.kt | 19 +++++ .../io/heapy/komok/tech/di/test2/ModuleD.kt | 24 ++++++ .../komok/tech/di/test2/SingletonTest.kt | 69 +++++++++++++++ .../heapy/komok/tech/di/ksp/BuilderClass.kt | 44 ++++++++-- .../komok/tech/di/ksp/FlattenModuleClass.kt | 5 +- .../tech/di/ksp/FlattenModuleFunction.kt | 9 +- .../komok/tech/di/ksp/KomokSymbolProcessor.kt | 2 - .../io/heapy/komok/business/serverModule.kt | 83 ------------------- .../io/heapy/komok/metrics/metricsModule.kt | 19 ----- .../komok/business/login/JwtServiceTest.kt | 4 +- 17 files changed, 228 insertions(+), 143 deletions(-) create mode 100644 .run/Komok.run.xml create mode 100644 komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleA.kt create mode 100644 komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleB.kt create mode 100644 komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleC.kt create mode 100644 komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleD.kt create mode 100644 komok-tech-di-test/src/test/kotlin/io/heapy/komok/tech/di/test2/SingletonTest.kt delete mode 100644 src/main/kotlin/io/heapy/komok/business/serverModule.kt delete mode 100644 src/main/kotlin/io/heapy/komok/metrics/metricsModule.kt diff --git a/.gitignore b/.gitignore index f7abd39..adc6af9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ build/ # Project src/main/resources/application.conf + +# System +.DS_Store diff --git a/.run/Komok.run.xml b/.run/Komok.run.xml new file mode 100644 index 0000000..c16a38d --- /dev/null +++ b/.run/Komok.run.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/BinderTest.kt b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/BinderTest.kt index a4507c6..a47c15a 100644 --- a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/BinderTest.kt +++ b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/BinderTest.kt @@ -50,15 +50,15 @@ class BasicBinderTest { } private val module1 by module { - provide(BasicBinderTest::Test1Impl) + provide(::Test1Impl) provide(::test2Provider) } private val module2 by module {} private val module3 by module { - provide(BasicBinderTest::Test3) - provide(BasicBinderTest::TestRoot) + provide(::Test3) + provide(::TestRoot) } @Test @@ -96,8 +96,8 @@ class SingletonBinderTest { fun test() = runTest { val module by module { - provide(SingletonBinderTest::Test1) - provide(SingletonBinderTest::TestRoot) + provide(::Test1) + provide(::TestRoot) } val root = createContextAndGet( @@ -125,7 +125,7 @@ class SingletonZeroArgBinderTest { runTest { val module by module { provideInstance({ Test1() }) - provide(SingletonZeroArgBinderTest::TestRoot) + provide(::TestRoot) } val root = createContextAndGet( @@ -148,7 +148,7 @@ class OptionalInjectionTest { class Bar private val module1 by module { - provide(OptionalInjectionTest::Foo) + provide(::Foo) } @Test @@ -196,9 +196,9 @@ class CyclicDependencyTest { class Baz(val foo: Foo) private val cyclic by module { - provide(CyclicDependencyTest::Foo) - provide(CyclicDependencyTest::Bar) - provide(CyclicDependencyTest::Baz) + provide(::Foo) + provide(::Bar) + provide(::Baz) } @Test diff --git a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointReturningTest.kt b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointReturningTest.kt index 45bfe3e..750a4df 100644 --- a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointReturningTest.kt +++ b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointReturningTest.kt @@ -9,9 +9,9 @@ class EntryPointReturningTest { fun `test inline module`() = runTest { val result = komok { - provide(EntryPointReturningTest::Application) - provide(EntryPointReturningTest::Service1) - provide(EntryPointReturningTest::Service2) + provide(::Application) + provide(::Service1) + provide(::Service2) } assertEquals( @@ -24,7 +24,7 @@ class EntryPointReturningTest { fun `test module`() = runTest { val result = komok { - provide(EntryPointReturningTest::Application) + provide(::Application) dependency(k1) } @@ -58,10 +58,10 @@ class EntryPointReturningTest { private val k1 by module { dependency(k2) - provide(EntryPointReturningTest::Service1) + provide(::Service1) } private val k2 by module { - provide(EntryPointReturningTest::Service2) + provide(::Service2) } } diff --git a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointTest.kt b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointTest.kt index 7e4c7ae..a7a5a5c 100644 --- a/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointTest.kt +++ b/komok-tech-di-ez/src/test/kotlin/io/heapy/komok/tech/di/ez/EntryPointTest.kt @@ -12,9 +12,9 @@ class EntryPointTest { assertFalse(TestInlineModule.executed) komok { - provide(EntryPointTest::TestInlineModule) - provide(EntryPointTest::Service1) - provide(EntryPointTest::Service2) + provide(::TestInlineModule) + provide(::Service1) + provide(::Service2) } assertTrue(TestInlineModule.executed) @@ -38,9 +38,9 @@ class EntryPointTest { runTest { val exception = assertThrows { komok, Unit> { - provide(EntryPointTest::TestInlineModule) - provide(EntryPointTest::Service1) - provide(EntryPointTest::Service2) + provide(::TestInlineModule) + provide(::Service1) + provide(::Service2) } } @@ -56,7 +56,7 @@ class EntryPointTest { assertFalse(TestModule.executed) komok { - provide(EntryPointTest::TestModule) + provide(::TestModule) dependency(k1) } @@ -92,10 +92,10 @@ class EntryPointTest { private val k1 by module { dependency(k2) - provide(EntryPointTest::Service1) + provide(::Service1) } private val k2 by module { - provide(EntryPointTest::Service2) + provide(::Service2) } } diff --git a/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleA.kt b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleA.kt new file mode 100644 index 0000000..129db97 --- /dev/null +++ b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleA.kt @@ -0,0 +1,12 @@ +package io.heapy.komok.tech.di.test2 + +import io.heapy.komok.tech.di.lib.Module + +class A + +@Module +open class ModuleA { + open val a by lazy { + A() + } +} diff --git a/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleB.kt b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleB.kt new file mode 100644 index 0000000..14d50f6 --- /dev/null +++ b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleB.kt @@ -0,0 +1,18 @@ +package io.heapy.komok.tech.di.test2 + +import io.heapy.komok.tech.di.lib.Module + +class B( + private val a: A, +) { + fun getA() = a +} + +@Module +open class ModuleB( + private val moduleA: ModuleA, +) { + open val b by lazy { + B(moduleA.a) + } +} diff --git a/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleC.kt b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleC.kt new file mode 100644 index 0000000..e34a43e --- /dev/null +++ b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleC.kt @@ -0,0 +1,19 @@ +package io.heapy.komok.tech.di.test2 + +import io.heapy.komok.tech.di.lib.Module + +class C( + private val a: A, +) { + fun getA() = + a +} + +@Module +open class ModuleC( + private val moduleA: ModuleA, +) { + open val c by lazy { + C(moduleA.a) + } +} diff --git a/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleD.kt b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleD.kt new file mode 100644 index 0000000..4dd6d5b --- /dev/null +++ b/komok-tech-di-test/src/main/kotlin/io/heapy/komok/tech/di/test2/ModuleD.kt @@ -0,0 +1,24 @@ +package io.heapy.komok.tech.di.test2 + +import io.heapy.komok.tech.di.lib.Module + +class D( + private val a: A, + private val b: B, + private val c: C, +) { + fun getAA() = a + fun getAB() = b.getA() + fun getAC() = c.getA() +} + +@Module +open class ModuleD( + private val moduleA: ModuleA, + private val moduleB: ModuleB, + private val moduleC: ModuleC, +) { + open val d by lazy { + D(moduleA.a, moduleB.b, moduleC.c) + } +} diff --git a/komok-tech-di-test/src/test/kotlin/io/heapy/komok/tech/di/test2/SingletonTest.kt b/komok-tech-di-test/src/test/kotlin/io/heapy/komok/tech/di/test2/SingletonTest.kt new file mode 100644 index 0000000..578e30a --- /dev/null +++ b/komok-tech-di-test/src/test/kotlin/io/heapy/komok/tech/di/test2/SingletonTest.kt @@ -0,0 +1,69 @@ +package io.heapy.komok.tech.di.test2 + +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.Assertions.assertSame +import org.junit.jupiter.api.Test + +class SingletonTest { + @Test + fun `test singleton`() { + val moduleD = createModuleD {} + + assertAll( + { assertSame(moduleD.d.getAA(), moduleD.d.getAB()) }, + { assertSame(moduleD.d.getAB(), moduleD.d.getAC()) }, + { assertSame(moduleD.d.getAA(), moduleD.d.getAC()) }, + ) + } + + @Test + fun `test singleton flatten`() { + val flat = createFlattenModuleD {} + + assertAll( + { assertSame(flat.moduleD.d.getAA(), flat.moduleD.d.getAB()) }, + { assertSame(flat.moduleD.d.getAB(), flat.moduleD.d.getAC()) }, + { assertSame(flat.moduleD.d.getAA(), flat.moduleD.d.getAC()) }, + { assertSame(flat.moduleA.a, flat.moduleD.d.getAA()) }, + ) + } + + @Test + fun `test singleton with override`() { + val a = A() + val moduleD = createModuleD { + moduleA { + a { + a + } + } + } + + assertAll( + { assertSame(moduleD.d.getAA(), moduleD.d.getAB()) }, + { assertSame(moduleD.d.getAB(), moduleD.d.getAC()) }, + { assertSame(moduleD.d.getAA(), moduleD.d.getAC()) }, + ) + } + + @Test + fun `test singleton with override flatten`() { + val a = A() + val flat = createFlattenModuleD { + moduleA { + a { + a + } + } + } + + assertAll( + { assertSame(a, flat.moduleD.d.getAA()) }, + { assertSame(a, flat.moduleD.d.getAB()) }, + { assertSame(a, flat.moduleD.d.getAC()) }, + { assertSame(a, flat.moduleA.a) }, + { assertSame(a, flat.moduleB.b.getA()) }, + { assertSame(a, flat.moduleC.c.getA()) }, + ) + } +} diff --git a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/BuilderClass.kt b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/BuilderClass.kt index 201f302..d620d92 100644 --- a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/BuilderClass.kt +++ b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/BuilderClass.kt @@ -105,19 +105,23 @@ private fun TypeSpec.Builder.addModuleBuildFunction( val primaryConstructor = module.primaryConstructor ?: error("MBF: Primary constructor not found for $className") - val moduleBuilderFunction = try { - FunSpec - .builder("build") - .returns( + val moduleBuildProperty = try { + PropertySpec + .builder( + "module", ClassName( packageName, - className, + className.overrideClassName(), ), + PRIVATE, ) - .addCode( + .mutable(false) + .delegate( buildCodeBlock { + add("lazy {\n") + indent() add( - "return %T(\n", + "%T(\n", ClassName( packageName, className.overrideClassName(), @@ -148,6 +152,32 @@ private fun TypeSpec.Builder.addModuleBuildFunction( } unindent() add(")\n") + unindent() + addStatement("}\n") + }, + ) + .build() + } catch (e: Exception) { + logger.error("Failed to generate module build property") + throw e + } + + addProperty(moduleBuildProperty) + + val moduleBuilderFunction = try { + FunSpec + .builder("build") + .returns( + ClassName( + packageName, + className, + ), + ) + .addCode( + buildCodeBlock { + addStatement( + "return module", + ) }, ) .build() diff --git a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleClass.kt b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleClass.kt index aed3c41..633fa11 100644 --- a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleClass.kt +++ b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleClass.kt @@ -11,17 +11,14 @@ fun String.flattenClassName(): String = "${this}Flatten" fun generateFlattenModuleClass( - graph: Map>, module: KSClassDeclaration, moduleDependencies: List, - sortedGraph: List, ): TypeSpec { val className = module.simpleName.asString() - val packageName = module.packageName.asString() return TypeSpec .classBuilder(className.flattenClassName()) - .addFlattenModuleClassConstructor(moduleDependencies) + .addFlattenModuleClassConstructor(moduleDependencies + module) .build() } diff --git a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleFunction.kt b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleFunction.kt index c45ec8d..9f689e3 100644 --- a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleFunction.kt +++ b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/FlattenModuleFunction.kt @@ -49,6 +49,7 @@ fun generateFlattenModuleFunction( return FunSpec .builder("createFlatten$className") + .addAnnotation(moduleDslMarker) .addParameter( "builder", LambdaTypeName.get( @@ -109,7 +110,13 @@ fun generateFlattenModuleFunction( indent() - moduleDependencies.forEach { + add( + "%N = %N,\n", + className.toPropertyName(), + className.toPropertyName(), + ) + + moduleDependencies.forEach { add( "%N = %N.build(),\n", it.toPropertyName(), diff --git a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/KomokSymbolProcessor.kt b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/KomokSymbolProcessor.kt index 404a71d..65a19ca 100644 --- a/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/KomokSymbolProcessor.kt +++ b/komok-tech-di/src/main/kotlin/io/heapy/komok/tech/di/ksp/KomokSymbolProcessor.kt @@ -66,8 +66,6 @@ class KomokSymbolProcessor( val flattenModuleClass = try { generateFlattenModuleClass( - graph = resolvedGraph, - sortedGraph = sortedGraph, module = module, moduleDependencies = moduleDependencies, ) diff --git a/src/main/kotlin/io/heapy/komok/business/serverModule.kt b/src/main/kotlin/io/heapy/komok/business/serverModule.kt deleted file mode 100644 index a23dbe8..0000000 --- a/src/main/kotlin/io/heapy/komok/business/serverModule.kt +++ /dev/null @@ -1,83 +0,0 @@ -@file:OptIn(ExperimentalSerializationApi::class) - -package io.heapy.komok.business - -import io.heapy.komok.business.login.JwtConfiguration -import io.heapy.komok.configuration.ConfigurationModule -import io.heapy.komok.metrics.MetricsModule -import io.heapy.komok.tech.di.lib.Module -import io.ktor.server.auth.* -import io.ktor.server.cio.* -import io.ktor.server.engine.* -import io.ktor.server.http.content.* -import io.ktor.server.routing.* -import io.micrometer.prometheusmetrics.PrometheusMeterRegistry -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.hocon.Hocon -import kotlinx.serialization.hocon.decodeFromConfig -import java.io.File - -@Module -open class ServerModule( - private val configModule: ConfigurationModule, - private val anonymousRoutesModule: AnonymousRoutesModule, - private val authenticatedRoutesModule: AuthenticatedRoutesModule, - private val metricsModule: MetricsModule, -) { - open val serverConfig: ServerConfiguration by lazy { - Hocon.decodeFromConfig(configModule.config.getConfig("server")) - } - - open val jwtConfig: JwtConfiguration by lazy { - Hocon.decodeFromConfig(configModule.config.getConfig("jwt")) - } - - open val server by lazy { - server( - anonymousRoutesModule.anonymousRoutes, - authenticatedRoutesModule.authenticatedRoutes, - serverConfig, - jwtConfig, - metricsModule.meterRegistry, - ) - } -} - -fun server( - anonymousRoutes: AnonymousRoutes, - authenticatedRoutes: AuthenticatedRoutes, - serverConfig: ServerConfiguration, - jwtConfig: JwtConfiguration, - meterRegistry: PrometheusMeterRegistry, -): ApplicationEngine { - return embeddedServer( - factory = CIO, - port = serverConfig.port, - host = serverConfig.host, - ) { - defaults(jwtConfig) - - routing { - staticFiles("/", File(serverConfig.resources)) { - preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP) - enableAutoHeadResponse() - } - - anonymousRoutes.run { - install() - } - - route("/api") { - authenticatedRoutes.run { - install() - } - } - - authenticate("jwt") { - - } - } - configureWebSockets() - configureMonitoring(meterRegistry) - } -} diff --git a/src/main/kotlin/io/heapy/komok/metrics/metricsModule.kt b/src/main/kotlin/io/heapy/komok/metrics/metricsModule.kt deleted file mode 100644 index 5991754..0000000 --- a/src/main/kotlin/io/heapy/komok/metrics/metricsModule.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.heapy.komok.metrics - -import io.heapy.komok.tech.di.lib.Module -import io.micrometer.common.util.internal.logging.InternalLoggerFactory -import io.micrometer.common.util.internal.logging.Slf4JLoggerFactory -import io.micrometer.prometheusmetrics.PrometheusConfig -import io.micrometer.prometheusmetrics.PrometheusMeterRegistry - -fun meterRegistry(): PrometheusMeterRegistry { - InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE) - return PrometheusMeterRegistry(PrometheusConfig.DEFAULT) -} - -@Module -open class MetricsModule { - open val meterRegistry by lazy { - meterRegistry() - } -} diff --git a/src/test/kotlin/io/heapy/komok/business/login/JwtServiceTest.kt b/src/test/kotlin/io/heapy/komok/business/login/JwtServiceTest.kt index c1ad585..9423c73 100644 --- a/src/test/kotlin/io/heapy/komok/business/login/JwtServiceTest.kt +++ b/src/test/kotlin/io/heapy/komok/business/login/JwtServiceTest.kt @@ -30,7 +30,7 @@ class JwtServiceTest : KomokBaseTest { } val module = createJwtModule { - configurationModule { + configModule { config(mockConfig) } } @@ -67,7 +67,7 @@ class JwtServiceTest : KomokBaseTest { } val module = createJwtModule { - configurationModule { + configModule { config(mockConfig) } }