@@ -29,6 +29,10 @@ import org.ktorm.ksp.spi.ColumnMetadata
2929import org.ktorm.ksp.spi.DatabaseNamingStrategy
3030import org.ktorm.ksp.spi.TableMetadata
3131import org.ktorm.schema.TypeReference
32+ import com.squareup.kotlinpoet.ClassName
33+ import com.squareup.kotlinpoet.asClassName
34+ import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
35+ import com.squareup.kotlinpoet.ksp.toClassName
3236import java.lang.reflect.InvocationTargetException
3337import java.util.*
3438import kotlin.reflect.jvm.jvmName
@@ -93,6 +97,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
9397
9498 _logger .info(" [ktorm-ksp-compiler] parse table metadata from entity: $className " )
9599 val table = cls.getAnnotationsByType(Table ::class ).first()
100+ val (superClass, superTableClasses) = parseSuperTableClass(cls)
101+ val allPropertyNamesOfSuperTables = superTableClasses.flatMap { it.getProperties(emptySet()) }.map { it.simpleName.asString() }
102+
96103 val tableMetadata = TableMetadata (
97104 entityClass = cls,
98105 name = table.name.ifEmpty { _databaseNamingStrategy .getTableName(cls) },
@@ -101,8 +108,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
101108 schema = table.schema.ifEmpty { _options [" ktorm.schema" ] }?.takeIf { it.isNotEmpty() },
102109 tableClassName = table.className.ifEmpty { _codingNamingStrategy .getTableClassName(cls) },
103110 entitySequenceName = table.entitySequenceName.ifEmpty { _codingNamingStrategy .getEntitySequenceName(cls) },
104- ignoreProperties = table.ignoreProperties.toSet(),
105- columns = ArrayList ()
111+ ignoreProperties = table.ignoreProperties.toSet() + allPropertyNamesOfSuperTables, // ignore properties of super tables
112+ columns = ArrayList (),
113+ superClass = superClass
106114 )
107115
108116 val columns = tableMetadata.columns as MutableList
@@ -274,6 +282,51 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
274282 )
275283 }
276284
285+ /* *
286+ * @return the super table class and all class be annotated with [SuperTableClass] in the inheritance hierarchy.
287+ */
288+ @OptIn(KotlinPoetKspPreview ::class )
289+ private fun parseSuperTableClass (cls : KSClassDeclaration ): Pair <ClassName , Set <KSClassDeclaration >> {
290+ val superTableClassAnnPair = cls.findAllAnnotationsInInheritanceHierarchy(SuperTableClass ::class .qualifiedName!! )
291+
292+ // if there is no SuperTableClass annotation, return the default super table class based on the class kind.
293+ if (superTableClassAnnPair.isEmpty()) {
294+ return if (cls.classKind == INTERFACE ) {
295+ org.ktorm.schema.Table ::class .asClassName() to emptySet()
296+ } else {
297+ org.ktorm.schema.BaseTable ::class .asClassName() to emptySet()
298+ }
299+ }
300+
301+ // SuperTableClass annotation can only be used on interface
302+ if (superTableClassAnnPair.map { it.first }.any { it.classKind != INTERFACE }) {
303+ val msg = " SuperTableClass annotation can only be used on interface."
304+ throw IllegalArgumentException (msg)
305+ }
306+
307+ // find the last annotation in the inheritance hierarchy
308+ val superTableClasses = superTableClassAnnPair
309+ .map { it.second }
310+ .map { it.arguments.single { it.name?.asString() == SuperTableClass ::value.name } }
311+ .map { it.value as KSType }
312+ .map { it.declaration as KSClassDeclaration }
313+
314+ var lowestSubClass = superTableClasses.first()
315+ for (i in 1 until superTableClasses.size) {
316+ val cur = superTableClasses[i]
317+ if (cur.isSubclassOf(lowestSubClass)) {
318+ lowestSubClass = cur
319+ } else if (! lowestSubClass.isSubclassOf(cur)) {
320+ val msg =
321+ " There are multiple SuperTableClass annotations in the inheritance hierarchy of class ${cls.qualifiedName?.asString()} ," +
322+ " but the values of annotation are not in the same inheritance hierarchy."
323+ throw IllegalArgumentException (msg)
324+ }
325+ }
326+ // TODO: to check All constructor parameters owned by `BaseTable` should also be owned by lowestSubClass.
327+ return lowestSubClass.toClassName() to superTableClasses.toSet()
328+ }
329+
277330 private fun TableMetadata.checkCircularRef (ref : KSClassDeclaration , stack : LinkedList <String > = LinkedList ()) {
278331 val className = this .entityClass.qualifiedName?.asString()
279332 val refClassName = ref.qualifiedName?.asString()
0 commit comments