diff --git a/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/Bear.kt b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/Bear.kt index 5cb809e7c..1baa31b8d 100644 --- a/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/Bear.kt +++ b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/Bear.kt @@ -1,6 +1,7 @@ package com.querydsl.example.ksp import com.querydsl.core.annotations.QueryProjection +import jakarta.persistence.Convert import jakarta.persistence.Entity import jakarta.persistence.Id @@ -9,7 +10,9 @@ class Bear( @Id val id: Int, val name: String, - val location: String + val location: String, + @Convert(converter = BearSpeciesConverter::class) + val species: BearSpecies? ) class BearSimplifiedProjection @QueryProjection constructor( diff --git a/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpecies.kt b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpecies.kt new file mode 100644 index 000000000..e617e1dc2 --- /dev/null +++ b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpecies.kt @@ -0,0 +1,9 @@ +package com.querydsl.example.ksp + +enum class BearSpecies { + BROWN_BEAR, + BLACK_BEAR, + POLAR_BEAR, + PANDA, + SUN_BEAR, +} diff --git a/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpeciesConverter.kt b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpeciesConverter.kt new file mode 100644 index 000000000..0a10d54c6 --- /dev/null +++ b/querydsl-examples/querydsl-example-ksp-codegen/src/main/kotlin/com/querydsl/example/ksp/BearSpeciesConverter.kt @@ -0,0 +1,22 @@ +package com.querydsl.example.ksp + +import jakarta.persistence.AttributeConverter +import jakarta.persistence.Converter + +@Converter +class BearSpeciesConverter : AttributeConverter { + + override fun convertToDatabaseColumn(attribute: BearSpecies?): String? { + return attribute?.name?.lowercase() + } + + override fun convertToEntityAttribute(dbData: String?): BearSpecies? { + return dbData?.let { + try { + BearSpecies.valueOf(it.uppercase()) + } catch (e: IllegalArgumentException) { + null + } + } + } +} diff --git a/querydsl-examples/querydsl-example-ksp-codegen/src/test/kotlin/Tests.kt b/querydsl-examples/querydsl-example-ksp-codegen/src/test/kotlin/Tests.kt index 75ecfd8f0..f55cadb1b 100644 --- a/querydsl-examples/querydsl-example-ksp-codegen/src/test/kotlin/Tests.kt +++ b/querydsl-examples/querydsl-example-ksp-codegen/src/test/kotlin/Tests.kt @@ -1,4 +1,5 @@ import com.querydsl.example.ksp.Bear +import com.querydsl.example.ksp.BearSpecies import com.querydsl.example.ksp.Cat import com.querydsl.example.ksp.CatType import com.querydsl.example.ksp.Dog @@ -181,7 +182,7 @@ class Tests { run { val em = emf.createEntityManager() em.transaction.begin() - em.persist(Bear(424, "Winnie", "The forest")) + em.persist(Bear(424, "Winnie", "The forest", null)) em.transaction.commit() em.close() } @@ -207,10 +208,40 @@ class Tests { @Test fun `query projection exclude property from constructor`() { - assertThat(Bear::class.declaredMemberProperties.count()).isEqualTo(3) + assertThat(Bear::class.declaredMemberProperties.count()).isEqualTo(4) assertThat(QBearSimplifiedProjection::class.primaryConstructor!!.parameters.count()).isEqualTo(2) } + @Test + fun `enum with convert annotation generates EnumPath`() { + val emf = initialize() + + run { + val em = emf.createEntityManager() + em.transaction.begin() + em.persist(Bear(501, "Baloo", "Jungle", null)) + em.transaction.commit() + em.close() + } + + run { + val em = emf.createEntityManager() + val queryFactory = JPAQueryFactory(em) + val q = QBear.bear + + val bears = queryFactory + .select(q.species.coalesce(BearSpecies.BLACK_BEAR)) + .from(q) + .orderBy(q.id.asc()) + .fetch() + + assertThat(bears.size).isEqualTo(1) + assertThat(bears[0]).isEqualTo(BearSpecies.BLACK_BEAR) + + em.close() + } + } + @Test fun `create and query dog with jsonb tag`() { val emf = initialize() diff --git a/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/TypeExtractor.kt b/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/TypeExtractor.kt index 165077602..23e6722f9 100644 --- a/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/TypeExtractor.kt +++ b/querydsl-tooling/querydsl-ksp-codegen/src/main/kotlin/com/querydsl/ksp/codegen/TypeExtractor.kt @@ -145,6 +145,10 @@ class TypeExtractor( } private fun userType(type: KSType): QPropertyType.Unknown? { + if (type.isEnum()) { + return null + } + val userTypeAnnotations = listOf( ClassName("org.hibernate.annotations", "Type"), ClassName("org.hibernate.annotations", "JdbcTypeCode"), @@ -204,3 +208,9 @@ private fun KSType.toClassNameSimple(): ClassName { else -> error("Could not compute ClassName for '$this'") } } + +private fun KSType.isEnum(): Boolean { + val referencedDeclaration = declaration + + return referencedDeclaration is KSClassDeclaration && referencedDeclaration.classKind == ClassKind.ENUM_CLASS +}