diff --git a/docs/en/jpql-with-kotlin-jdsl/paths.md b/docs/en/jpql-with-kotlin-jdsl/paths.md index 8d1828479..76e145985 100644 --- a/docs/en/jpql-with-kotlin-jdsl/paths.md +++ b/docs/en/jpql-with-kotlin-jdsl/paths.md @@ -13,6 +13,77 @@ entity(Book::class, "b").path(Book::isbn).path(Isbn::value) entity(Book::class, "b")(Book::isbn)(Isbn::value) ``` +## Java entity + +`path()` and `invoke()` can take `KProperty1` or `KFuction1` as an argument. +`KFunction1` is useful when you use Java entity with private property and public getter. + +```java +@Entity +public class Book { + @Id + private Long id; + + private String title; + + public String getTitle() { + return title; + } +} +``` + +```kotlin +// compile error +path(Book::title) + +// Book.title +path(Book::getTitle) +``` + +Kotlin JDSL infers the property name from the getter with the following rules: + +- If the name starts with `is`, use the name as it is. +- If the name starts with `get`, remove `get` and change the first letter to lowercase. +- Otherwise, use the name as it is. + +```kotlin +// Book.isAvailable +path(Book::isAvailable) + +// Book.available +path(Book::getAvailable) +``` + +If you want to use your own rule instead of the above rules, you can implement `JpqlPropertyIntrospector` and provide it to `RenderContext`. +See [Custom DSL](./custom-dsl.md) for more details. +If you are using Spring, see [Spring supports](./spring-supports.md) also. + +```kotlin +class MyIntrospector : JpqlPropertyIntrospector() { + override fun introspect(property: KCallable<*>): JpqlPropertyDescription? { + if (property is KFunction1<*, *>) { + // resolve a name with your own rule + val name = ... + return MyProperty(name) + } + + return null + } + + private data class MyProperty( + override val name: String, + ) : JpqlPropertyDescription +} + +val myModule = object : JpqlRenderModule { + override fun setupModule(context: JpqlRenderModule.SetupContext) { + context.prependIntrospector(MyIntrospector()) + } +} + +val myContext = JpqlRenderContext().registerModule(myModule) +``` + ## Expression `Path` can be used as [`Expression`](expressions.md), such as in a [select clause](statements.md#select-clause) or [predicate](predicates.md). diff --git a/docs/en/jpql-with-kotlin-jdsl/spring-supports.md b/docs/en/jpql-with-kotlin-jdsl/spring-supports.md index 160bc3325..0ec5b7fb6 100644 --- a/docs/en/jpql-with-kotlin-jdsl/spring-supports.md +++ b/docs/en/jpql-with-kotlin-jdsl/spring-supports.md @@ -5,7 +5,7 @@ Kotlin JDSL supports Spring Boot AutoConfigure. If you have Spring Boot and `com.linecorp.kotlin-jdsl:spring-data-jpa-support` or `com.linecorp.kotlin-jdsl:spring-batch-support` dependency together, the `JpqlRenderContext` bean is created by AutoConfiguration. -If you declare your `JpqlSerializer` as a bean, it will be included with the `JpqlRenderContext` bean. +If you declare your `JpqlSerializer` or `JpqlIntrospector` as a bean, it will be included with the `JpqlRenderContext` bean. ## Spring Data Repository diff --git a/docs/ko/jpql-with-kotlin-jdsl/paths.md b/docs/ko/jpql-with-kotlin-jdsl/paths.md index 53d651403..a55a7d1d7 100644 --- a/docs/ko/jpql-with-kotlin-jdsl/paths.md +++ b/docs/ko/jpql-with-kotlin-jdsl/paths.md @@ -13,6 +13,77 @@ entity(Book::class, "b").path(Book::isbn).path(Isbn::value) entity(Book::class, "b")(Book::isbn)(Isbn::value) ``` +## Java entity + +`path()` 와 `invoke()`는 `KProperty1` 또는 `KFuction1`를 인자로 받습니다. +`KFunction1`의 경우, getter만 public인 Java로 선언한 entity를 사용할 때 유용합니다. + +```java +@Entity +public class Book { + @Id + private Long id; + + private String title; + + public String getTitle() { + return title; + } +} +``` + +```kotlin +// compile error +path(Book::title) + +// Book.title +path(Book::getTitle) +``` + +Kotlin JDSL은 getter 이름에서 프로퍼티 이름을 추론하기 위해 다음 규칙을 따릅니다. + +- `is`로 시작하는 경우 이름 그대로 사용합니다. +- `get`으로 시작하는 경우 `get`을 제거하고 이후 첫 글자를 소문자로 변경합니다. +- 그 외의 경우, 이름 그대로 사용합니다. + +```kotlin +// Book.isAvailable +path(Book::isAvailable) + +// Book.available +path(Book::getAvailable) +``` + +위 규칙 대신 나만의 규칙을 사용하고 싶다면, `JpqlPropertyIntrospector`를 구현하고 이를 이를 `RenderContext`에 추가해야 합니다. +더 자세한 내용은 [Custom DSL](./custom-dsl.md)을 참고하세요. +Spring을 사용하고 있다면 [Spring supports](./spring-supports.md)도 참고하세요. + +```kotlin +class MyIntrospector : JpqlPropertyIntrospector() { + override fun introspect(property: KCallable<*>): JpqlPropertyDescription? { + if (property is KFunction1<*, *>) { + // 나만의 규칙으로 이름을 추론합니다 + val name = ... + return MyProperty(name) + } + + return null + } + + private data class MyProperty( + override val name: String, + ) : JpqlPropertyDescription +} + +val myModule = object : JpqlRenderModule { + override fun setupModule(context: JpqlRenderModule.SetupContext) { + context.prependIntrospector(MyIntrospector()) + } +} + +val myContext = JpqlRenderContext().registerModule(myModule) +``` + ## Expression `Path`는 [select clause](statements.md#select-clause) 나 [predicate](predicates.md) 등에서 [`Expression`](expressions.md)으로 사용될 수 있습니다. diff --git a/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md b/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md index 52f75c1ab..6eee9c598 100644 --- a/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md +++ b/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md @@ -5,7 +5,7 @@ Kotlin JDSL은 Spring Boot AutoConfigure를 지원합니다. 만약 프로젝트가 Spring Boot와 `com.linecorp.kotlin-jdsl:spring-data-jpa-support` dependency를 같이 포함하고 있다면, `JpqlRenderContext` bean이 `KotlinJdslAutoConfiguration`를 통해 자동 생성 됩니다. -만약 `JpqlSerializer`를 bean으로 선언했다면, 자동으로 `JpqlRenderContext`에 해당 bean이 포함됩니다. +만약 `JpqlSerializer` 또는 `JpqlIntrospector`를 bean으로 선언했다면, 자동으로 `JpqlRenderContext`에 해당 bean이 포함됩니다. ## Spring Data Repository diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt index af755fd75..e680ff6f5 100644 --- a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt +++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt @@ -41,6 +41,7 @@ import java.math.BigDecimal import java.math.BigInteger import kotlin.internal.Exact import kotlin.reflect.KClass +import kotlin.reflect.KFunction1 import kotlin.reflect.KProperty1 /** @@ -194,6 +195,15 @@ open class Jpql : JpqlDsl { return Paths.path(property) } + /** + * Creates a path expression with the property. + * The path starts from the entity which is the owner of the property. + */ + @SinceJdsl("3.1.0") + fun path(getter: KFunction1): Path { + return Paths.path(getter) + } + /** * Creates a path expression with the entity and property. */ @@ -202,6 +212,14 @@ open class Jpql : JpqlDsl { return Paths.path(this.toEntity(), property) } + /** + * Creates a path expression with the entity and property. + */ + @SinceJdsl("3.1.0") + fun Entityable.path(getter: KFunction1): Path { + return Paths.path(this.toEntity(), getter) + } + /** * Creates a path expression with the path and property. */ @@ -210,6 +228,14 @@ open class Jpql : JpqlDsl { return Paths.path(this.toPath(), property) } + /** + * Creates a path expression with the path and property. + */ + @SinceJdsl("3.1.0") + fun Pathable.path(getter: KFunction1): Path { + return Paths.path(this.toPath(), getter) + } + /** * Creates a path expression with the entity and property. */ @@ -218,6 +244,14 @@ open class Jpql : JpqlDsl { return Paths.path(this.toEntity(), property) } + /** + * Creates a path expression with the entity and property. + */ + @SinceJdsl("3.1.0") + operator fun Entityable.invoke(getter: KFunction1): Path { + return Paths.path(this.toEntity(), getter) + } + /** * Creates a path expression with the path and property. */ @@ -226,6 +260,14 @@ open class Jpql : JpqlDsl { return Paths.path(this.toPath(), property) } + /** + * Creates a path expression with the path and property. + */ + @SinceJdsl("3.1.0") + operator fun Pathable.invoke(getter: KFunction1): Path { + return Paths.path(this.toPath(), getter) + } + /** * Creates an aliased expression with the alias expression. * The aliased expression can be referenced by the alias expression. diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt index bb9d6e9e7..4f4181793 100644 --- a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt +++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt @@ -10,6 +10,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths import org.assertj.core.api.WithAssertions import org.junit.jupiter.api.Test +import java.math.BigDecimal class PathDslTest : WithAssertions { private val entity1 = Entities.entity(FullTimeEmployee::class) @@ -33,6 +34,23 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `path() with a getter`() { + // when + val path = queryPart { + path(FullTimeEmployee::getMonthlySalary) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + FullTimeEmployee::getMonthlySalary, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `path() with a entity and a property`() { // when @@ -51,6 +69,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `path() with a entity and a getter`() { + // when + val path = queryPart { + entity1.path(FullTimeEmployee::getMonthlySalary) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + entity1, + FullTimeEmployee::getMonthlySalary, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `path() with a path and a property`() { // when @@ -69,6 +105,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `path() with a path and a getter`() { + // when + val path = queryPart { + path1.path(FullTimeEmployee::getMonthlySalary) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + path1, + FullTimeEmployee::getMonthlySalary, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `path() with a entity and a property of super class`() { // when @@ -87,6 +141,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `path() with a entity and a getter of super class`() { + // when + val path = queryPart { + entity1.path(Employee::getDisplayName) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + entity1, + Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `path() with a path and a property of super class`() { // when @@ -105,6 +177,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `path() with a path and a getter of super class`() { + // when + val path = queryPart { + path1.path(Employee::getDisplayName) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + path1, + Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `invoke() with a entity and a property`() { // when @@ -123,6 +213,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `invoke() with a entity and a getter`() { + // when + val path = queryPart { + entity1(FullTimeEmployee::getMonthlySalary) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + entity1, + FullTimeEmployee::getMonthlySalary, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `invoke() with a path and a property`() { // when @@ -141,6 +249,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `invoke() with a path and a getter`() { + // when + val path = queryPart { + path1(FullTimeEmployee::getMonthlySalary) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + path1, + FullTimeEmployee::getMonthlySalary, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `invoke() with a entity and a property of super class`() { // when @@ -159,6 +285,24 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + @Test + fun `invoke() with a entity and a getter of super class`() { + // when + val path = queryPart { + entity1(Employee::getDisplayName) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + entity1, + Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(excepted) + } + @Test fun `invoke() with a path and a property of super class`() { // when @@ -176,4 +320,22 @@ class PathDslTest : WithAssertions { assertThat(actual).isEqualTo(excepted) } + + @Test + fun `invoke() with a path and a getter of super class`() { + // when + val path = queryPart { + path1(Employee::getDisplayName) + } + + val actual: Path = path // for type check + + // then + val excepted = Paths.path( + path1, + Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(excepted) + } } diff --git a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt index 3d1c808c3..293ce31bb 100644 --- a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt +++ b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt @@ -7,4 +7,6 @@ abstract class Employee( val phone: String, val address: EmployeeAddress, val departments: MutableSet, -) +) { + fun getDisplayName() = nickname ?: name +} diff --git a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt index 09bb8b9fc..6eb177bb8 100644 --- a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt +++ b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt @@ -17,4 +17,6 @@ class FullTimeEmployee( phone = phone, address = address, departments = departments, -) +) { + fun getMonthlySalary() = annualSalary.div(BigDecimal.valueOf(12)) +} diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt index b97a13840..90d5d6b81 100644 --- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt @@ -9,6 +9,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathProperty import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathTreat import kotlin.internal.Exact import kotlin.reflect.KClass +import kotlin.reflect.KFunction1 import kotlin.reflect.KProperty1 /** @@ -26,6 +27,16 @@ object Paths { return JpqlEntityProperty(Entities.entity(owner), property) } + /** + * Creates a path with the property. + */ + @SinceJdsl("3.1.0") + fun path(getter: KFunction1): Path { + val owner = PropertyUtils.getOwner(getter) + + return JpqlEntityProperty(Entities.entity(owner), getter) + } + /** * Creates a path with the entity and property. */ @@ -34,6 +45,14 @@ object Paths { return JpqlEntityProperty(entity, property) } + /** + * Creates a path with the entity and property. + */ + @SinceJdsl("3.1.0") + fun path(entity: Entity, getter: KFunction1): Path { + return JpqlEntityProperty(entity, getter) + } + /** * Creates a path with the path and property. */ @@ -42,6 +61,14 @@ object Paths { return JpqlPathProperty(path, property) } + /** + * Creates a path with the path and property. + */ + @SinceJdsl("3.1.0") + fun path(path: Path, getter: KFunction1): Path { + return JpqlPathProperty(path, getter) + } + /** * Creates a path with downcasting. */ diff --git a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt index d68e002bc..62a8bfeed 100644 --- a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt +++ b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt @@ -18,7 +18,7 @@ class PathsTest : WithAssertions { private val path2 = Paths.treat(Paths.path(EmployeeDepartment::employee), FullTimeEmployee::class) @Test - fun path() { + fun `path() with a property`() { // when val actual = Paths.path( FullTimeEmployee::address, @@ -33,6 +33,22 @@ class PathsTest : WithAssertions { assertThat(actual).isEqualTo(expected) } + @Test + fun `path() with a getter`() { + // when + val actual = Paths.path( + FullTimeEmployee::getDisplayName, + ) + + // then + val expected = JpqlEntityProperty( + entity = Entities.entity(FullTimeEmployee::class), + property = FullTimeEmployee::getDisplayName, + ) + + assertThat(actual).isEqualTo(expected) + } + @Test fun `path() with an entity`() { // when @@ -50,6 +66,23 @@ class PathsTest : WithAssertions { assertThat(actual).isEqualTo(expected) } + @Test + fun `path() with an entity and a getter`() { + // when + val actual = Paths.path( + entity1, + Employee::getDisplayName, + ) + + // then + val expected = JpqlEntityProperty( + entity = entity1, + property = Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(expected) + } + @Test fun `path() with a path`() { // when @@ -67,6 +100,23 @@ class PathsTest : WithAssertions { assertThat(actual).isEqualTo(expected) } + @Test + fun `path() with a path and a getter`() { + // when + val actual = Paths.path( + path1, + getter = Employee::getDisplayName, + ) + + // then + val expected = JpqlPathProperty( + path = path1, + property = Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(expected) + } + @Test fun `path() with an entity and a property of super class`() { // when @@ -84,6 +134,23 @@ class PathsTest : WithAssertions { assertThat(actual).isEqualTo(expected) } + @Test + fun `path() with an entity and a getter of super class`() { + // when + val actual = Paths.path( + entity2, + Employee::getDisplayName, + ) + + // then + val expected = JpqlEntityProperty( + entity = entity2, + property = Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(expected) + } + @Test fun `path() with a path and a property of super class`() { // when @@ -101,6 +168,23 @@ class PathsTest : WithAssertions { assertThat(actual).isEqualTo(expected) } + @Test + fun `path() with a path and a getter of super class`() { + // when + val actual = Paths.path( + path2, + getter = Employee::getDisplayName, + ) + + // then + val expected = JpqlPathProperty( + path = path2, + property = Employee::getDisplayName, + ) + + assertThat(actual).isEqualTo(expected) + } + @Test fun treat() { // when diff --git a/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt b/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt index 534c41239..2eae684e0 100644 --- a/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt +++ b/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt @@ -9,4 +9,6 @@ abstract class Employee( val phone: String, val address: EmployeeAddress, val departments: MutableSet, -) +) { + fun getDisplayName() = nickname ?: name +} diff --git a/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt b/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt index ccbe84052..461adee71 100644 --- a/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt +++ b/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt @@ -2,6 +2,7 @@ package com.linecorp.kotlinjdsl.property import kotlin.jvm.internal.CallableReference import kotlin.reflect.KClass +import kotlin.reflect.KFunction1 import kotlin.reflect.KProperty1 object PropertyUtils { @@ -9,4 +10,9 @@ object PropertyUtils { @Suppress("UNCHECKED_CAST") return (property as CallableReference).owner as KClass } + + fun getOwner(property: KFunction1): KClass { + @Suppress("UNCHECKED_CAST") + return (property as CallableReference).owner as KClass + } } diff --git a/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt index 860dc230d..a11d7b2fc 100644 --- a/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt +++ b/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt @@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.support.spring.batch.javax.autoconfigure import com.linecorp.kotlinjdsl.render.RenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer import com.linecorp.kotlinjdsl.support.spring.batch.javax.item.database.orm.KotlinJdslQueryProviderFactory import org.springframework.boot.autoconfigure.AutoConfiguration @@ -15,14 +16,22 @@ import org.springframework.context.annotation.Bean open class KotlinJdslAutoConfiguration { @Bean @ConditionalOnMissingBean - open fun jpqlRenderContext(serializers: List>): JpqlRenderContext { - val userDefinedSerializers = object : JpqlRenderModule { + open fun jpqlRenderContext( + serializers: List>, + introspectors: List, + ): JpqlRenderContext { + val userDefinedModule = object : JpqlRenderModule { override fun setupModule(context: JpqlRenderModule.SetupContext) { context.addAllSerializer(serializers.reversed()) + + introspectors.reversed().forEach { + context.prependIntrospector(it) + } } } - return JpqlRenderContext().registerModules(userDefinedSerializers) + return JpqlRenderContext() + .registerModules(userDefinedModule) } @Bean diff --git a/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt index 7bf20121d..bb15084bb 100644 --- a/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt +++ b/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt @@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.support.spring.batch.autoconfigure import com.linecorp.kotlinjdsl.render.RenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer import com.linecorp.kotlinjdsl.support.spring.batch.item.database.orm.KotlinJdslQueryProviderFactory import org.springframework.boot.autoconfigure.AutoConfiguration @@ -15,14 +16,22 @@ import org.springframework.context.annotation.Bean open class KotlinJdslAutoConfiguration { @Bean @ConditionalOnMissingBean - open fun jpqlRenderContext(serializers: List>): JpqlRenderContext { - val userDefinedSerializers = object : JpqlRenderModule { + open fun jpqlRenderContext( + serializers: List>, + introspectors: List, + ): JpqlRenderContext { + val userDefinedModule = object : JpqlRenderModule { override fun setupModule(context: JpqlRenderModule.SetupContext) { context.addAllSerializer(serializers.reversed()) + + introspectors.reversed().forEach { + context.prependIntrospector(it) + } } } - return JpqlRenderContext().registerModules(userDefinedSerializers) + return JpqlRenderContext() + .registerModules(userDefinedModule) } @Bean diff --git a/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt index 3840e882d..144b98ad1 100644 --- a/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt +++ b/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt @@ -4,6 +4,7 @@ import com.linecorp.kotlinjdsl.SinceJdsl import com.linecorp.kotlinjdsl.render.RenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer import com.linecorp.kotlinjdsl.support.spring.data.jpa.javax.repository.KotlinJdslJpqlExecutor import com.linecorp.kotlinjdsl.support.spring.data.jpa.javax.repository.KotlinJdslJpqlExecutorImpl @@ -20,15 +21,22 @@ open class KotlinJdslAutoConfiguration { @Bean @ConditionalOnMissingBean @SinceJdsl("3.0.0") - open fun jpqlRenderContext(serializers: List>): JpqlRenderContext { - val userDefinedSerializers = object : JpqlRenderModule { + open fun jpqlRenderContext( + serializers: List>, + introspectors: List, + ): JpqlRenderContext { + val userDefinedModule = object : JpqlRenderModule { override fun setupModule(context: JpqlRenderModule.SetupContext) { context.addAllSerializer(serializers.reversed()) + + introspectors.reversed().forEach { + context.prependIntrospector(it) + } } } return JpqlRenderContext() - .registerModules(userDefinedSerializers) + .registerModules(userDefinedModule) } @Bean diff --git a/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt index f5454b4cb..ee9415a7a 100644 --- a/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt +++ b/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt @@ -4,6 +4,7 @@ import com.linecorp.kotlinjdsl.SinceJdsl import com.linecorp.kotlinjdsl.render.RenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule +import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer import com.linecorp.kotlinjdsl.support.spring.data.jpa.repository.KotlinJdslJpqlExecutor import com.linecorp.kotlinjdsl.support.spring.data.jpa.repository.KotlinJdslJpqlExecutorImpl @@ -20,15 +21,22 @@ open class KotlinJdslAutoConfiguration { @Bean @ConditionalOnMissingBean @SinceJdsl("3.0.0") - open fun jpqlRenderContext(serializers: List>): JpqlRenderContext { - val userDefinedSerializers = object : JpqlRenderModule { + open fun jpqlRenderContext( + serializers: List>, + introspectors: List, + ): JpqlRenderContext { + val userDefinedModule = object : JpqlRenderModule { override fun setupModule(context: JpqlRenderModule.SetupContext) { context.addAllSerializer(serializers.reversed()) + + introspectors.reversed().forEach { + context.prependIntrospector(it) + } } } return JpqlRenderContext() - .registerModules(userDefinedSerializers) + .registerModules(userDefinedModule) } @Bean