From 9de2e4ad43548f2efb851210033e83530de75278 Mon Sep 17 00:00:00 2001 From: Jake Son Date: Fri, 10 Nov 2023 08:36:03 +0900 Subject: [PATCH] refactor(render): separate property and class introspector --- .../render/jpql/JpqlRenderContext.kt | 3 + .../introspector/JpqlEntityIntrospector.kt | 12 +++ .../introspector/JpqlPropertyIntrospector.kt | 12 +++ .../impl/JakartaJpqlIntrospector.kt | 25 +----- .../impl/JavaxJpqlIntrospector.kt | 25 +----- .../jpql/introspector/impl/JpqlProperty.kt | 7 -- .../KotlinStyleJpqlPropertyIntrospector.kt | 33 ++++++++ .../impl/JakartaJpqlIntrospectorTest.kt | 78 +----------------- .../impl/JavaxJpqlIntrospectorTest.kt | 74 +---------------- ...KotlinStyleJpqlPropertyIntrospectorTest.kt | 80 +++++++++++++++++++ 10 files changed, 152 insertions(+), 197 deletions(-) create mode 100644 render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt create mode 100644 render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt delete mode 100644 render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JpqlProperty.kt create mode 100644 render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt create mode 100644 render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt index 47380d5b0..422be8953 100644 --- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt @@ -9,6 +9,7 @@ import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospectorModifier import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.JakartaJpqlIntrospector import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.JavaxJpqlIntrospector +import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.KotlinStyleJpqlPropertyIntrospector import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializerModifier @@ -246,6 +247,8 @@ private class DefaultModule : JpqlRenderModule { context.appendIntrospector(JakartaJpqlIntrospector()) } + context.appendIntrospector(KotlinStyleJpqlPropertyIntrospector()) + context.addAllSerializer( JpqlAliasedExpressionSerializer(), JpqlAndSerializer(), diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt new file mode 100644 index 000000000..30024b3b4 --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt @@ -0,0 +1,12 @@ +package com.linecorp.kotlinjdsl.render.jpql.introspector + +import com.linecorp.kotlinjdsl.SinceJdsl +import kotlin.reflect.KCallable + +/** + * Abstract class to get the entity information by introspecting KClass. + */ +@SinceJdsl("3.1.0") +abstract class JpqlEntityIntrospector : JpqlIntrospector { + override fun introspect(property: KCallable<*>): JpqlPropertyDescription? = null +} diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt new file mode 100644 index 000000000..99347270e --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt @@ -0,0 +1,12 @@ +package com.linecorp.kotlinjdsl.render.jpql.introspector + +import com.linecorp.kotlinjdsl.SinceJdsl +import kotlin.reflect.KClass + +/** + * Abstract class to get the entity information by introspecting KCallable. + */ +@SinceJdsl("3.1.0") +abstract class JpqlPropertyIntrospector : JpqlIntrospector { + override fun introspect(type: KClass<*>): JpqlEntityDescription? = null +} diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt index 82a8e9a4d..b7f75b54b 100644 --- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt @@ -2,19 +2,15 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl import com.linecorp.kotlinjdsl.Internal import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityDescription -import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector -import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription -import kotlin.reflect.KCallable +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityIntrospector import kotlin.reflect.KClass -import kotlin.reflect.KFunction1 -import kotlin.reflect.KProperty1 import kotlin.reflect.full.findAnnotations /** - * Introspector that introspects KClass and KCallable using [jakarta.persistence.Entity]. + * Introspector that introspects KClass using [jakarta.persistence.Entity]. */ @Internal -class JakartaJpqlIntrospector : JpqlIntrospector { +class JakartaJpqlIntrospector : JpqlEntityIntrospector() { override fun introspect(type: KClass<*>): JpqlEntityDescription? { val entity = type.findAnnotations(jakarta.persistence.Entity::class).firstOrNull() @@ -24,21 +20,6 @@ class JakartaJpqlIntrospector : JpqlIntrospector { null } } - - override fun introspect(property: KCallable<*>): JpqlPropertyDescription? { - return when (property) { - is KProperty1<*, *> -> JpqlProperty(property.name) - is KFunction1<*, *> -> JpqlProperty(resolvePropertyName(property)) - else -> null - } - } - - private fun resolvePropertyName(getter: KFunction1<*, *>): String = - if (getter.name.startsWith("is")) { - getter.name - } else { - getter.name.removePrefix("get").replaceFirstChar { it.lowercase() } - } } private data class JakartaEntity( diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt index 1cd7c6f87..3effe861d 100644 --- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt @@ -2,19 +2,15 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl import com.linecorp.kotlinjdsl.Internal import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityDescription -import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector -import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription -import kotlin.reflect.KCallable +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityIntrospector import kotlin.reflect.KClass -import kotlin.reflect.KFunction1 -import kotlin.reflect.KProperty1 import kotlin.reflect.full.findAnnotations /** - * Introspector that introspects KClass and KCallable using [javax.persistence.Entity]. + * Introspector that introspects KClass using [javax.persistence.Entity]. */ @Internal -class JavaxJpqlIntrospector : JpqlIntrospector { +class JavaxJpqlIntrospector : JpqlEntityIntrospector() { override fun introspect(type: KClass<*>): JpqlEntityDescription? { val entity = type.findAnnotations(javax.persistence.Entity::class).firstOrNull() @@ -24,21 +20,6 @@ class JavaxJpqlIntrospector : JpqlIntrospector { null } } - - override fun introspect(property: KCallable<*>): JpqlPropertyDescription? { - return when (property) { - is KProperty1<*, *> -> JpqlProperty(property.name) - is KFunction1<*, *> -> JpqlProperty(resolvePropertyName(property)) - else -> null - } - } - - private fun resolvePropertyName(getter: KFunction1<*, *>): String = - if (getter.name.startsWith("is")) { - getter.name - } else { - getter.name.removePrefix("get").replaceFirstChar { it.lowercase() } - } } private data class JavaxEntity( diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JpqlProperty.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JpqlProperty.kt deleted file mode 100644 index 47e2aae20..000000000 --- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JpqlProperty.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.linecorp.kotlinjdsl.render.jpql.introspector.impl - -import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription - -internal data class JpqlProperty( - override val name: String, -) : JpqlPropertyDescription diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt new file mode 100644 index 000000000..fc60d4db0 --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt @@ -0,0 +1,33 @@ +package com.linecorp.kotlinjdsl.render.jpql.introspector.impl + +import com.linecorp.kotlinjdsl.Internal +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyIntrospector +import kotlin.reflect.KCallable +import kotlin.reflect.KFunction1 +import kotlin.reflect.KProperty1 + +/** + * Introspector that introspects a property name in KCallable using Kotlin style. + */ +@Internal +class KotlinStyleJpqlPropertyIntrospector : JpqlPropertyIntrospector() { + override fun introspect(property: KCallable<*>): JpqlPropertyDescription? { + return when (property) { + is KProperty1<*, *> -> KotlinStyleProperty(property.name) + is KFunction1<*, *> -> KotlinStyleProperty(resolvePropertyName(property)) + else -> null + } + } + + private fun resolvePropertyName(getter: KFunction1<*, *>): String = + if (getter.name.startsWith("is")) { + getter.name + } else { + getter.name.removePrefix("get").replaceFirstChar { it.lowercase() } + } +} + +private data class KotlinStyleProperty( + override val name: String, +) : JpqlPropertyDescription diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt index 0b5962e58..743e544c0 100644 --- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt @@ -1,9 +1,7 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl -import io.mockk.mockkClass import org.assertj.core.api.WithAssertions import org.junit.jupiter.api.Test -import kotlin.reflect.KProperty0 class JakartaJpqlIntrospectorTest : WithAssertions { private val sut = JakartaJpqlIntrospector() @@ -13,7 +11,7 @@ class JakartaJpqlIntrospectorTest : WithAssertions { } @Test - fun `introspect(type) returns name of entity annotation, when entity annotation has name`() { + fun `introspect() returns name of entity annotation, when entity annotation has name`() { // given val type = EntityClass1::class @@ -25,7 +23,7 @@ class JakartaJpqlIntrospectorTest : WithAssertions { } @Test - fun `introspect(type) returns name of class, when entity annotation does not have name`() { + fun `introspect() returns name of class, when entity annotation does not have name`() { // given val type = EntityClass2::class @@ -37,7 +35,7 @@ class JakartaJpqlIntrospectorTest : WithAssertions { } @Test - fun `introspect(type) returns null, when there is no entity annotation`() { + fun `introspect() returns null, when there is no entity annotation`() { // given val type = NonEntityCLass1::class @@ -48,76 +46,8 @@ class JakartaJpqlIntrospectorTest : WithAssertions { assertThat(actual?.name).isNull() } - @Test - fun `introspect(property) returns property name, when property is KProperty1`() { - // given - val property = EntityClass1::property1 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("property1") - } - - @Test - fun `introspect(property) returns property name with prefix removed, when getter name starts with get`() { - // given - val property = EntityClass1::getProperty2 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("property2") - } - - @Test - fun `introspect(property) returns property name as is, when getter name starts with is`() { - // given - val property = EntityClass1::isProperty3 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("isProperty3") - } - - @Test - fun `introspect(property) returns property name as is, when getter name does not start with get or is`() { - // given - val property = EntityClass1::someProperty - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("someProperty") - } - - @Test - fun `introspect(property) returns null, when property is not KProperty1 or KFunction1`() { - // given - val property = mockkClass(KProperty0::class) - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isNull() - } - @jakarta.persistence.Entity(name = ENTITY_NAME_1) - private open class EntityClass1 { - val property1: Long = 0 - - fun getProperty2(): Long = 100 - - fun isProperty3(): Boolean = true - - fun someProperty(): String = "someProperty" - } + private open class EntityClass1 @jakarta.persistence.Entity private open class EntityClass2 diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt index f8d70a923..4b161c54d 100644 --- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt @@ -1,9 +1,7 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl -import io.mockk.mockkClass import org.assertj.core.api.WithAssertions import org.junit.jupiter.api.Test -import kotlin.reflect.KProperty0 class JavaxJpqlIntrospectorTest : WithAssertions { private val sut = JavaxJpqlIntrospector() @@ -13,7 +11,7 @@ class JavaxJpqlIntrospectorTest : WithAssertions { } @Test - fun `introspect(type) returns name of entity annotation, when entity annotation has name`() { + fun `introspect() returns name of entity annotation, when entity annotation has name`() { // given val type = EntityClass1::class @@ -48,76 +46,8 @@ class JavaxJpqlIntrospectorTest : WithAssertions { assertThat(actual?.name).isNull() } - @Test - fun `introspect(property) returns property name, when property is KProperty1`() { - // given - val property = EntityClass1::property1 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("property1") - } - - @Test - fun `introspect(property) returns property name with prefix removed, when getter name starts with get`() { - // given - val property = EntityClass1::getProperty2 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("property2") - } - - @Test - fun `introspect(property) returns property name as is, when getter name starts with is`() { - // given - val property = EntityClass1::isProperty3 - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("isProperty3") - } - - @Test - fun `introspect(property) returns property name as is, when getter name does not start with get or is`() { - // given - val property = EntityClass1::someProperty - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isEqualTo("someProperty") - } - - @Test - fun `introspect(property) returns null, when property is not KProperty1 or KFunction1`() { - // given - val property = mockkClass(KProperty0::class) - - // when - val actual = sut.introspect(property) - - // then - assertThat(actual?.name).isNull() - } - @javax.persistence.Entity(name = ENTITY_NAME_1) - private open class EntityClass1 { - val property1: Long = 0 - - fun getProperty2(): Long = 100 - - fun isProperty3(): Boolean = true - - fun someProperty(): String = "someProperty" - } + private open class EntityClass1 @javax.persistence.Entity private open class EntityClass2 diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt new file mode 100644 index 000000000..e5bff4570 --- /dev/null +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt @@ -0,0 +1,80 @@ +package com.linecorp.kotlinjdsl.render.jpql.introspector.impl + +import io.mockk.mockkClass +import org.assertj.core.api.WithAssertions +import org.junit.jupiter.api.Test +import kotlin.reflect.KProperty0 + +class KotlinStyleJpqlPropertyIntrospectorTest : WithAssertions { + private val sut = KotlinStyleJpqlPropertyIntrospector() + + @Test + fun `introspect() returns property name, when property is KProperty1`() { + // given + val property = EntityClass1::property1 + + // when + val actual = sut.introspect(property) + + // then + assertThat(actual?.name).isEqualTo("property1") + } + + @Test + fun `introspect() returns property name with prefix removed, when getter name starts with get`() { + // given + val property = EntityClass1::getProperty2 + + // when + val actual = sut.introspect(property) + + // then + assertThat(actual?.name).isEqualTo("property2") + } + + @Test + fun `introspect() returns property name as is, when getter name starts with is`() { + // given + val property = EntityClass1::isProperty3 + + // when + val actual = sut.introspect(property) + + // then + assertThat(actual?.name).isEqualTo("isProperty3") + } + + @Test + fun `introspect() returns property name as is, when getter name does not start with get or is`() { + // given + val property = EntityClass1::someProperty + + // when + val actual = sut.introspect(property) + + // then + assertThat(actual?.name).isEqualTo("someProperty") + } + + @Test + fun `introspect() returns null, when property is not KProperty1 or KFunction1`() { + // given + val property = mockkClass(KProperty0::class) + + // when + val actual = sut.introspect(property) + + // then + assertThat(actual?.name).isNull() + } + + private class EntityClass1 { + val property1: Long = 0 + + fun getProperty2(): Long = 100 + + fun isProperty3(): Boolean = true + + fun someProperty(): String = "someProperty" + } +}