From 1ea8c2996e4c4c1ef2fbf09e4c2181453df0077d Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Wed, 8 Jan 2025 11:06:16 +0100 Subject: [PATCH 1/2] create BaseModels for Schemas --- .../crystalprocessor/model/EntityFactory.kt | 15 +++++- .../processing/model/ModelWorkSet.kt | 36 +++++++------ .../processing/model/ModelWorker.kt | 6 +-- .../validation/model/ModelValidation.kt | 13 ++--- .../CouchbaseBaseBinderProcessorKotlinTest.kt | 53 +++++++++++++++++++ .../src/test/resources/ExpectedSubSchema.txt | 26 +++++++++ 6 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 crystal-map-processor/src/test/resources/ExpectedSubSchema.txt diff --git a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/model/EntityFactory.kt b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/model/EntityFactory.kt index adee8697..ff2ddfdf 100644 --- a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/model/EntityFactory.kt +++ b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/model/EntityFactory.kt @@ -40,7 +40,7 @@ object EntityFactory { ) as EntityHolder } - fun createBaseModelHolder( + fun createWrapperBaseModelHolder( sourceModel: ISourceModel, allWrapperPaths: List ): BaseModelHolder { @@ -53,6 +53,19 @@ object EntityFactory { ) as BaseModelHolder } + fun createSchemaBaseModelHolder( + sourceModel: ISourceModel, + allSchemaClassPaths: List + ): BaseModelHolder { + return create( + sourceModel, + BaseModelHolder(sourceModel), + allSchemaClassPaths, + emptyMap(), + SCHEMA_SUB_ENTITY_SUFFIX + ) as BaseModelHolder + } + fun createChildEntityHolder( sourceModel: ISourceModel, allWrapperPaths: List, diff --git a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorkSet.kt b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorkSet.kt index 0bcaf151..1eefc1af 100644 --- a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorkSet.kt +++ b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorkSet.kt @@ -35,7 +35,9 @@ class ModelWorkSet( private val schemaModels: MutableMap = HashMap() - private val baseModels: MutableMap = HashMap() + private val wrapperBaseModels: MutableMap = HashMap() + + private val schemaBaseModels: MutableMap = HashMap() private val typeConverterModels: MutableMap = HashMap() @@ -66,21 +68,27 @@ class ModelWorkSet( override fun loadModels(logger: Logger, env: ProcessingEnvironment) { val allWrapperPaths = allWrapperElements.map { element -> element.toString() } + val allSchemaClassPaths = allSchemaClassElements.map { element -> element.toString() } for (element in allBaseModelElements) { - val baseModel = - EntityFactory.createBaseModelHolder(SourceModel(element), allWrapperPaths) - baseModels[element.toString()] = baseModel + val wrapperBaseModel = EntityFactory.createWrapperBaseModelHolder(SourceModel(element), allWrapperPaths) + wrapperBaseModels[element.toString()] = wrapperBaseModel + + val schemaBaseModel = EntityFactory.createSchemaBaseModelHolder(SourceModel(element), allSchemaClassPaths) + schemaBaseModels[element.toString()] = schemaBaseModel } // we can resolve the based on chain when all base models are parsed. - for (baseModel in baseModels.values) { - EntityFactory.addBasedOn(baseModel.sourceElement, baseModels, baseModel) + for (baseModel in wrapperBaseModels.values) { + EntityFactory.addBasedOn(baseModel.sourceElement, wrapperBaseModels, baseModel) + } + + for (baseModel in schemaBaseModels.values) { + EntityFactory.addBasedOn(baseModel.sourceElement, schemaBaseModels, baseModel) } for (element in allEntityElements) { - val entityModel = - EntityFactory.createEntityHolder(SourceModel(element), allWrapperPaths, baseModels) + val entityModel = EntityFactory.createEntityHolder(SourceModel(element), allWrapperPaths, wrapperBaseModels) entityModels[element.toString()] = entityModel entityModel.reducesModels.forEach { @@ -90,7 +98,7 @@ class ModelWorkSet( it ), allWrapperPaths, - baseModels + wrapperBaseModels ) reduced.isReduced = true entityModels[reduced.entitySimpleName] = reduced @@ -101,7 +109,7 @@ class ModelWorkSet( val wrapperModel = EntityFactory.createChildEntityHolder( SourceModel(element), allWrapperPaths, - baseModels + wrapperBaseModels ) wrapperModels[element.toString()] = wrapperModel @@ -112,19 +120,18 @@ class ModelWorkSet( it ), allWrapperPaths, - baseModels + wrapperBaseModels ) reduced.isReduced = true entityModels[reduced.entitySimpleName] = reduced } } - val allSchemaClassPaths = allSchemaClassElements.map { element -> element.toString() } for (element in allSchemaClassElements) { val schemaModel = EntityFactory.createSchemaEntityHolder( SourceModel(element), allSchemaClassPaths, - baseModels + schemaBaseModels ) schemaModels[element.toString()] = schemaModel } @@ -145,7 +152,6 @@ class ModelWorkSet( ModelValidation( logger, - baseModels, wrapperModels, entityModels, typeConverterModels.values.toList(), @@ -166,7 +172,7 @@ class ModelWorkSet( get() = schemaModels.keys.toList() val bases: List - get() = baseModels.values.toList() + get() = wrapperBaseModels.values.toList() val typeConverters: List get() = typeConverterModels.values.toList() diff --git a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt index 080e4636..19c47997 100644 --- a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt +++ b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt @@ -78,7 +78,7 @@ class ModelWorker(override val logger: Logger, override val codeGenerator: CodeG WrapperGeneration().generateModel(it, useSuspend, typeConvertersByConvertedClass) } - process(workSet.schemas, generatedInterfaces, useSuspend, typeConvertersByConvertedClass) { + process(workSet.schemas) { SchemaGeneration().generateModel(it, workSet.schemaClassPaths, typeConvertersByConvertedClass) } @@ -89,13 +89,9 @@ class ModelWorker(override val logger: Logger, override val codeGenerator: CodeG private fun process( models: List, - generatedInterfaces: MutableSet, - useSuspend: Boolean, - typeConvertersByConvertedClass: Map, generate: (T) -> FileSpec ) { for (model in models) { - generateInterface(generatedInterfaces, model, useSuspend, typeConvertersByConvertedClass) documentationGenerator?.addEntitySegments(model) schemaGenerator?.addEntity(model) entityRelationshipGenerator?.addEntityNodes(model) diff --git a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/validation/model/ModelValidation.kt b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/validation/model/ModelValidation.kt index 08d6716d..6baefe17 100644 --- a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/validation/model/ModelValidation.kt +++ b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/validation/model/ModelValidation.kt @@ -1,13 +1,12 @@ package com.schwarz.crystalprocessor.validation.model +import com.schwarz.crystalapi.Reduce +import com.schwarz.crystalapi.TypeConverter +import com.schwarz.crystalapi.deprecated.DeprecatedField import com.schwarz.crystalprocessor.Logger import com.schwarz.crystalprocessor.model.entity.BaseEntityHolder -import com.schwarz.crystalprocessor.model.entity.BaseModelHolder import com.schwarz.crystalprocessor.model.entity.EntityHolder import com.schwarz.crystalprocessor.model.entity.WrapperEntityHolder -import com.schwarz.crystalapi.Reduce -import com.schwarz.crystalapi.TypeConverter -import com.schwarz.crystalapi.deprecated.DeprecatedField import com.schwarz.crystalprocessor.model.typeconverter.ImportedTypeConverterHolder import com.schwarz.crystalprocessor.model.typeconverter.TypeConverterHolder import com.schwarz.crystalprocessor.model.typeconverter.TypeConverterHolderForEntityGeneration @@ -17,7 +16,6 @@ import com.squareup.kotlinpoet.ParameterizedTypeName class ModelValidation( val logger: Logger, - val baseModels: MutableMap, val wrapperModels: MutableMap, val entityModels: MutableMap, val typeConverterModels: List, @@ -197,7 +195,10 @@ class ModelValidation( private fun validateTypeConversions() { typeConverterModels.forEach { if (!nonConvertibleClassesTypeNames.contains(it.mapClassTypeName)) { - logger.error("Invalid map type ${it.mapClassTypeName} found in TypeConverter ${it.classTypeName}. Should be one of $nonConvertibleClassesTypeNames", null) + logger.error( + "Invalid map type ${it.mapClassTypeName} found in TypeConverter ${it.classTypeName}. Should be one of $nonConvertibleClassesTypeNames", + null + ) } } diff --git a/crystal-map-processor/src/test/java/com/schwarz/CouchbaseBaseBinderProcessorKotlinTest.kt b/crystal-map-processor/src/test/java/com/schwarz/CouchbaseBaseBinderProcessorKotlinTest.kt index 436c4a13..3d0ba7d8 100644 --- a/crystal-map-processor/src/test/java/com/schwarz/CouchbaseBaseBinderProcessorKotlinTest.kt +++ b/crystal-map-processor/src/test/java/com/schwarz/CouchbaseBaseBinderProcessorKotlinTest.kt @@ -251,6 +251,59 @@ class CouchbaseBaseBinderProcessorKotlinTest { Assert.assertEquals(expected, actual) } + @Test + fun testKotlinSchemaGenerationWithBasedOn() { + val expected = File("src/test/resources/ExpectedSubSchema.txt").readLines() + val testObject = SourceFile.kotlin( + "TestObject.kt", + PACKAGE_HEADER + + "import com.schwarz.crystalapi.Fields\n" + + "import com.schwarz.crystalapi.Field\n" + + "import com.schwarz.crystalapi.MapWrapper\n" + + "import com.schwarz.crystalapi.SchemaClass\n" + + "@MapWrapper\n" + + "@SchemaClass\n" + + "@Fields(\n" + + "Field(name = \"type\", type = String::class, defaultValue = \"test\", readonly = true)\n" + + ")\n" + + "open class TestObject" + ) + val base = SourceFile.kotlin( + "Base.kt", + PACKAGE_HEADER + + "import com.schwarz.crystalapi.BaseModel\n" + + "import com.schwarz.crystalapi.Fields\n" + + "import com.schwarz.crystalapi.Field\n" + + "@BaseModel\n" + + "@Fields(\n" + + "Field(name = \"someObject\", type = TestObject::class)\n" + + ")\n" + + "open class Base" + ) + val sub = SourceFile.kotlin( + "Sub.kt", + PACKAGE_HEADER + + "import com.kaufland.testModels.TestObject\n" + + "import com.schwarz.crystalapi.BasedOn\n" + + "import com.schwarz.crystalapi.Field\n" + + "import com.schwarz.crystalapi.Fields\n" + + "import com.schwarz.crystalapi.SchemaClass\n" + + "import java.time.OffsetDateTime\n" + + "@SchemaClass\n" + + "@BasedOn(Base::class)\n" + + "@Fields(\n" + + "Field(name = \"type\", type = String::class, defaultValue = \"sub\", readonly = true)\n" + + ")\n" + + "class Sub" + ) + val compilation = compileKotlin(base, testObject, sub) + + val actual = compilation.generatedFiles.find { it.name == "SubSchema.kt" }!!.readLines() + + Assert.assertEquals(KotlinCompilation.ExitCode.OK, compilation.exitCode) + Assert.assertEquals(expected, actual) + } + @Test fun testKotlinPrivateGeneration() { val subEntity = SourceFile.kotlin( diff --git a/crystal-map-processor/src/test/resources/ExpectedSubSchema.txt b/crystal-map-processor/src/test/resources/ExpectedSubSchema.txt new file mode 100644 index 00000000..74f774fb --- /dev/null +++ b/crystal-map-processor/src/test/resources/ExpectedSubSchema.txt @@ -0,0 +1,26 @@ +// DO NOT EDIT THIS FILE. +// Generated using Crystal-Map +// +// Do not edit this class!!!!. +// +package com.kaufland.testModels + +import com.schwarz.crystalapi.schema.CMJsonField +import com.schwarz.crystalapi.schema.CMObjectField +import com.schwarz.crystalapi.schema.Schema +import kotlin.String + +public open class SubSchema( + path: String = "", +) : Schema { + public val DEFAULT_TYPE: String = "sub" + + public val type: CMJsonField = CMJsonField("type", path) + + public val someObject: CMObjectField = CMObjectField( + com.kaufland.testModels.TestObjectSchema(if (path.isBlank()) "someObject" else + "$path.someObject"), + "someObject", + path, + ) +} \ No newline at end of file From 34a28ec2d324f3fa0e25df11b7e11e6535a67e69 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Wed, 8 Jan 2025 15:09:10 +0100 Subject: [PATCH 2/2] specify type and renaming --- .../crystalprocessor/processing/model/ModelWorker.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt index 19c47997..5eebfb49 100644 --- a/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt +++ b/crystal-map-processor/src/main/java/com/schwarz/crystalprocessor/processing/model/ModelWorker.kt @@ -20,6 +20,7 @@ import com.schwarz.crystalprocessor.generation.model.TypeConverterObjectGenerati import com.schwarz.crystalprocessor.generation.model.WrapperGeneration import com.schwarz.crystalprocessor.meta.SchemaGenerator import com.schwarz.crystalprocessor.model.entity.BaseEntityHolder +import com.schwarz.crystalprocessor.model.entity.SchemaClassHolder import com.schwarz.crystalprocessor.model.typeconverter.TypeConverterHolderForEntityGeneration import com.schwarz.crystalprocessor.processing.Worker import com.squareup.kotlinpoet.FileSpec @@ -87,11 +88,8 @@ class ModelWorker(override val logger: Logger, override val codeGenerator: CodeG schemaGenerator?.generate() } - private fun process( - models: List, - generate: (T) -> FileSpec - ) { - for (model in models) { + private fun process(schemaModels: List, generate: (SchemaClassHolder) -> FileSpec) { + for (model in schemaModels) { documentationGenerator?.addEntitySegments(model) schemaGenerator?.addEntity(model) entityRelationshipGenerator?.addEntityNodes(model)