Skip to content

Commit 998aad0

Browse files
authored
Render object arrays as Kotlin Array<T> in querydsl-kotlin-codegen (#1790) (#1791)
Render object arrays as Kotlin Array<T> in querydsl-kotlin-codegen Object array properties (e.g. String[]) were emitted with Java array syntax (ArrayPath<String[], String> = createArray("tags", String[]::class.java)), which is not valid Kotlin and fails to compile. Map object arrays to the Kotlin Array<T> type and the Array<T>::class.java class literal, while keeping primitive arrays (int[], byte[], ...) on their dedicated Kotlin array classes (IntArray, ByteArray, ...). Fixes #1790 Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com>
1 parent 1512fdd commit 998aad0

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

querydsl-tooling/querydsl-kotlin-codegen/src/main/kotlin/com/querydsl/kotlin/codegen/Extensions.kt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,26 @@ import com.squareup.kotlinpoet.asTypeName
2727
import com.squareup.kotlinpoet.joinToCode
2828
import kotlin.reflect.KClass
2929

30+
private val PRIMITIVE_ARRAY_FULL_NAMES =
31+
setOf("boolean[]", "byte[]", "char[]", "short[]", "int[]", "long[]", "float[]", "double[]")
32+
33+
// Component type of an object array (e.g. String[]), or null for non-arrays and primitive
34+
// arrays. Primitive arrays (int[], byte[], ...) keep their dedicated Kotlin array class
35+
// (IntArray, ByteArray, ...) via asClassName() and must not be wrapped in Array<T>.
36+
private fun Type.objectArrayComponentType(): Type? =
37+
componentType?.takeUnless { fullName in PRIMITIVE_ARRAY_FULL_NAMES }
38+
3039
@JvmOverloads
31-
fun Type.asTypeName(out: Boolean = false): TypeName = asClassName().let { className ->
32-
if (parameters.isNotEmpty())
33-
className.parameterizedBy(*parameters.map { if (out) it.asOutTypeName() else it.asTypeName() }.toTypedArray()) else className
40+
fun Type.asTypeName(out: Boolean = false): TypeName {
41+
// Object arrays (e.g. String[]) must be rendered as the Kotlin Array<T> type.
42+
objectArrayComponentType()?.let { component ->
43+
return Array::class.asClassName()
44+
.parameterizedBy(if (out) component.asOutTypeName() else component.asTypeName())
45+
}
46+
return asClassName().let { className ->
47+
if (parameters.isNotEmpty())
48+
className.parameterizedBy(*parameters.map { if (out) it.asOutTypeName() else it.asTypeName() }.toTypedArray()) else className
49+
}
3450
}
3551

3652
fun Type.asClassName(): ClassName = when (this.fullName) {
@@ -67,7 +83,10 @@ private fun Type.enclosingTypeHierarchy(): List<String> {
6783

6884
fun ClassName.asClassStatement() = CodeBlock.of("%T::class.java", this)
6985

70-
fun Type.asClassNameStatement() = asClassName().asClassStatement()
86+
fun Type.asClassNameStatement(): CodeBlock =
87+
// Object arrays need the Kotlin Array<T>::class.java form to resolve to the right runtime class.
88+
objectArrayComponentType()?.let { CodeBlock.of("%T::class.java", asTypeName()) }
89+
?: asClassName().asClassStatement()
7190

7291
fun TypeMappings.getPathClassName(type: Type, model: EntityType) = getPathType(type, model, true).asClassName()
7392

querydsl-tooling/querydsl-kotlin-codegen/src/test/kotlin/com/querydsl/kotlin/codegen/EntitySerializerTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ class EntitySerializerTest {
117117
assertCompiles("QEntity", writer.toString())
118118
}
119119

120+
@Test
121+
fun object_array() {
122+
val type = SimpleType(TypeCategory.ENTITY, "Entity", "", "Entity", false, false)
123+
val entityType = EntityType(type)
124+
entityType.addProperty(Property(entityType, "tags", ClassType(TypeCategory.ARRAY, Array<String>::class.java)))
125+
typeMappings.register(entityType, queryTypeFactory.create(entityType))
126+
serializer.serialize(entityType, SimpleSerializerConfig.DEFAULT, JavaWriter(writer))
127+
Assertions.assertTrue(writer.toString().contains("val tags: ArrayPath<Array<String>, String>"))
128+
Assertions.assertTrue(writer.toString().contains("createArray(\"tags\", Array<String>::class.java)"))
129+
assertCompiles("QEntity", writer.toString())
130+
}
131+
120132
@Test
121133
fun include() {
122134
val type = SimpleType(TypeCategory.ENTITY, "Entity", "", "Entity", false, false)

0 commit comments

Comments
 (0)