From a9422dccc7b7486fbf11025b3e982eef2abe5496 Mon Sep 17 00:00:00 2001 From: craftyworks Date: Sat, 16 Aug 2025 01:46:35 +0900 Subject: [PATCH] Inner class naming in KSP to match KAPT behavior - Change queryClassName generation to use underscore separator for nested classes - Maintains compatibility with existing KAPT-generated Q-classes - Add comprehensive test cases for inner class naming scenarios Fixes: Inner classes now generate QOuterClass_InnerClass instead of QInnerClass This ensures seamless migration from KAPT to KSP without breaking existing code. --- .../ksp/codegen/QueryModelExtractor.kt | 9 +++- .../src/test/kotlin/RenderTest.kt | 52 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/QueryModelExtractor.kt b/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/QueryModelExtractor.kt index 2db706271..071facea9 100644 --- a/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/QueryModelExtractor.kt +++ b/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/QueryModelExtractor.kt @@ -154,9 +154,16 @@ class QueryModelExtractor( companion object { fun queryClassName(classDeclaration: KSClassDeclaration, settings: KspSettings): ClassName { + val simpleNames = generateSequence(classDeclaration) { it.parentDeclaration as? KSClassDeclaration } + .map { it.simpleName.asString() } + .toList() + .reversed() + + val className = simpleNames.joinToString("_") + return ClassName( "${classDeclaration.packageName.asString()}${settings.packageSuffix}", - "${settings.prefix}${classDeclaration.simpleName.asString()}${settings.suffix}" + "${settings.prefix}${className}${settings.suffix}" ) } } diff --git a/querydsl-tooling/querydsl-ksp-codegen/src/test/kotlin/RenderTest.kt b/querydsl-tooling/querydsl-ksp-codegen/src/test/kotlin/RenderTest.kt index be89d0373..ba2b2e075 100644 --- a/querydsl-tooling/querydsl-ksp-codegen/src/test/kotlin/RenderTest.kt +++ b/querydsl-tooling/querydsl-ksp-codegen/src/test/kotlin/RenderTest.kt @@ -211,6 +211,48 @@ class RenderTest { ) : com.querydsl.core.types.ConstructorExpression(CatDTO::class.java, arrayOf(kotlin.Int::class.java, kotlin.String::class.java), id, name) """.trimIndent()) } + + @Test + fun innerClassNaming() { + // Test case for inner class naming compatibility with KAPT + val model = QueryModel( + originalClassName = ClassName("", "OuterClass", "InnerClass"), + typeParameterCount = 0, + className = ClassName("", "QOuterClass_InnerClass"), + type = QueryModelType.ENTITY, + null, + mockk() + ) + val properties = listOf( + QProperty("innerProperty", QPropertyType.Simple(SimpleType.QString)) + ) + model.properties.addAll(properties) + val typeSpec = QueryModelRenderer.render(model) + val code = typeSpec.toString() + + // Skip compile check for inner classes as they reference non-existent types + code.assertContains("class QOuterClass_InnerClass") + code.assertContains("val innerProperty: com.querydsl.core.types.dsl.StringPath = createString(\"innerProperty\")") + } + + @Test + fun deeplyNestedClassNaming() { + // Test case for deeply nested classes (3 levels) - just check generated code structure + val model = QueryModel( + originalClassName = ClassName("", "Level1", "Level2", "Level3"), + typeParameterCount = 0, + className = ClassName("", "QLevel1_Level2_Level3"), + type = QueryModelType.ENTITY, + null, + mockk() + ) + val typeSpec = QueryModelRenderer.render(model) + val code = typeSpec.toString() + + // Skip compile check for nested classes as they reference non-existent types + code.assertContains("class QLevel1_Level2_Level3") + code.assertContains("EntityPathBase") + } } private fun String.assertLines(expected: String) { @@ -271,3 +313,13 @@ class QAnimal( class Cat class CatDTO + +class OuterClass { + class InnerClass +} + +class Level1 { + class Level2 { + class Level3 + } +} \ No newline at end of file