) Stream.of(type.getDeclaredConstructors())
diff --git a/databind/src/main/java/tech/ydb/yoj/databind/schema/reflect/StdReflector.java b/databind/src/main/java/tech/ydb/yoj/databind/schema/reflect/StdReflector.java
index 6394765c..d2c89646 100644
--- a/databind/src/main/java/tech/ydb/yoj/databind/schema/reflect/StdReflector.java
+++ b/databind/src/main/java/tech/ydb/yoj/databind/schema/reflect/StdReflector.java
@@ -11,8 +11,8 @@
import static java.util.Comparator.comparing;
/**
- * Standard {@link Reflector} implementation, suitable for most usages. By default, reflecting record classes, POJOs and
- * simple types such as {@code int} is supported.
+ * Standard {@link Reflector} implementation, suitable for most usages. By default, reflecting record classes, Kotlin
+ * data classes, POJOs and simple types such as {@code int} is supported.
*
* You can override default {@link Reflector} by creating a custom {@link SchemaRegistry} with your own instance of
* {@code StdReflector} with a different set of {@link TypeFactory type factories}, or a wholly different implementation
@@ -26,6 +26,7 @@
public final class StdReflector implements Reflector {
public static final Reflector instance = new StdReflector(List.of(
RecordType.FACTORY,
+ KotlinDataClassTypeFactory.instance,
PojoType.FACTORY,
SimpleType.FACTORY
));
diff --git a/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinJvmRecordSchemaTest.kt b/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinJvmRecordSchemaTest.kt
new file mode 100644
index 00000000..f2864b1f
--- /dev/null
+++ b/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinJvmRecordSchemaTest.kt
@@ -0,0 +1,117 @@
+package tech.ydb.yoj.databind.schema
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.BeforeClass
+import org.junit.Test
+
+class KotlinJvmRecordSchemaTest {
+ @Test
+ fun testRawPathField() {
+ val field = schema!!.getField("entity1")
+
+ assertThat(field.rawPath).isEqualTo("entity1")
+ }
+
+ @Test
+ fun testRawPathSubField() {
+ val field = schema!!.getField("entity1.entity2.entity3")
+
+ assertThat(field.rawPath).isEqualTo("entity1.entity2.entity3")
+ }
+
+ @Test
+ fun testRawPathLeafField() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.rawPath).isEqualTo("entity1.entity2.entity3.value")
+ }
+
+ @Test
+ fun testRawSubPathSubField() {
+ val field = schema!!.getField("entity1.entity2.entity3")
+
+ assertThat(field.getRawSubPath(1)).isEqualTo("entity2.entity3")
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldOnlyLead() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(3)).isEqualTo("value")
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldEqualNesting() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(4)).isEmpty()
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldExceedsNesting() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(10)).isEmpty()
+ }
+
+ @Test
+ fun testIsFlatTrue() {
+ assertThat(schema!!.getField("flatEntity").isFlat).isTrue()
+ }
+
+ @Test
+ fun testIdsFlatFalse() {
+ assertThat(schema!!.getField("twoFieldEntity").isFlat).isFalse()
+ }
+
+ @Test
+ fun testIsFlatFalseForNotFlat() {
+ assertThat(schema!!.getField("notFlatEntity").isFlat).isFalse()
+ }
+
+ private class TestSchema(entityType: Class) : Schema(entityType)
+
+ @JvmRecord
+ private data class UberEntity(
+ val entity1: Entity1,
+ val flatEntity: FlatEntity,
+ val twoFieldEntity: TwoFieldEntity,
+ val notFlatEntity: NotFlatEntity,
+ )
+
+ @JvmRecord
+ private data class Entity1(val entity2: Entity2)
+
+ @JvmRecord
+ private data class Entity2(val entity3: Entity3)
+
+ @JvmRecord
+ private data class Entity3(val value: Int)
+
+ @JvmRecord
+ private data class FlatEntity(val entity1: Entity1)
+
+ @JvmRecord
+ private data class TwoFieldEntity(
+ val entity1: Entity1,
+ val boolValue: Boolean,
+ )
+
+ @JvmRecord
+ private data class NotFlatEntity(
+ val twoFieldEntity: TwoFieldEntity,
+ val otherTwoFieldEntity: TwoFieldEntity,
+ )
+
+ companion object {
+ private var schema: Schema? = null
+
+ @JvmStatic
+ @BeforeClass
+ fun setUpClass() {
+ schema = TestSchema(
+ UberEntity::class.java
+ )
+ }
+ }
+}
diff --git a/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinSchemaTest.kt b/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinSchemaTest.kt
new file mode 100644
index 00000000..eb4c0ef7
--- /dev/null
+++ b/databind/src/test/kotlin/tech/ydb/yoj/databind/schema/KotlinSchemaTest.kt
@@ -0,0 +1,110 @@
+package tech.ydb.yoj.databind.schema
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.BeforeClass
+import org.junit.Test
+
+class KotlinSchemaTest {
+ @Test
+ fun testRawPathField() {
+ val field = schema!!.getField("entity1")
+
+ assertThat(field.rawPath).isEqualTo("entity1")
+ }
+
+ @Test
+ fun testRawPathSubField() {
+ val field = schema!!.getField("entity1.entity2.entity3")
+
+ assertThat(field.rawPath).isEqualTo("entity1.entity2.entity3")
+ }
+
+ @Test
+ fun testRawPathLeafField() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.rawPath).isEqualTo("entity1.entity2.entity3.value")
+ }
+
+ @Test
+ fun testRawSubPathSubField() {
+ val field = schema!!.getField("entity1.entity2.entity3")
+
+ assertThat(field.getRawSubPath(1)).isEqualTo("entity2.entity3")
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldOnlyLead() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(3)).isEqualTo("value")
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldEqualNesting() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(4)).isEmpty()
+ }
+
+ @Test
+ fun testRawSubPathLeafFieldExceedsNesting() {
+ val field = schema!!.getField("entity1.entity2.entity3.value")
+
+ assertThat(field.getRawSubPath(10)).isEmpty()
+ }
+
+ @Test
+ fun testIsFlatTrue() {
+ assertThat(schema!!.getField("flatEntity").isFlat).isTrue()
+ }
+
+ @Test
+ fun testIdsFlatFalse() {
+ assertThat(schema!!.getField("twoFieldEntity").isFlat).isFalse()
+ }
+
+ @Test
+ fun testIsFlatFalseForNotFlat() {
+ assertThat(schema!!.getField("notFlatEntity").isFlat).isFalse()
+ }
+
+ private class TestSchema(entityType: Class) : Schema(entityType)
+
+ private data class UberEntity(
+ val entity1: Entity1,
+ val flatEntity: FlatEntity,
+ val twoFieldEntity: TwoFieldEntity,
+ val notFlatEntity: NotFlatEntity,
+ )
+
+ private data class Entity1(val entity2: Entity2)
+
+ private data class Entity2(val entity3: Entity3)
+
+ private data class Entity3(val value: Int)
+
+ private data class FlatEntity(val entity1: Entity1)
+
+ private data class TwoFieldEntity(
+ val entity1: Entity1,
+ val boolValue: Boolean,
+ )
+
+ private data class NotFlatEntity(
+ val twoFieldEntity: TwoFieldEntity,
+ val otherTwoFieldEntity: TwoFieldEntity,
+ )
+
+ companion object {
+ private var schema: Schema? = null
+
+ @JvmStatic
+ @BeforeClass
+ fun setUpClass() {
+ schema = TestSchema(
+ UberEntity::class.java
+ )
+ }
+ }
+}
diff --git a/databind/src/test/resources/log4j2.yaml b/databind/src/test/resources/log4j2.yaml
new file mode 100644
index 00000000..5dfc2a3f
--- /dev/null
+++ b/databind/src/test/resources/log4j2.yaml
@@ -0,0 +1,15 @@
+Configuration:
+ appenders:
+ Console:
+ name: stdout
+ PatternLayout:
+ Pattern: "%d %-5level %-6X{tx} [%t] %c{1.}: %msg%n%throwable"
+
+ Loggers:
+ Root:
+ level: info
+ AppenderRef:
+ ref: stdout
+ Logger:
+ - name: tech.ydb.yoj.databind
+ level: debug
diff --git a/pom.xml b/pom.xml
index bf880236..df497d7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
pom
YDB ORM for Java (YOJ)
@@ -132,6 +132,9 @@
2.14.0
2.10.1
+
+ 1.9.22
+
4.13.2
2.2
@@ -369,6 +372,11 @@
none
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
@@ -631,6 +639,18 @@
gson
${gson-version}
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ ${kotlin.version}
+ true
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${kotlin.version}
+ true
+
diff --git a/repository-inmemory/pom.xml b/repository-inmemory/pom.xml
index fdd37874..82b37c27 100644
--- a/repository-inmemory/pom.xml
+++ b/repository-inmemory/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/repository-test/pom.xml b/repository-test/pom.xml
index 64fc1462..ae0af7ce 100644
--- a/repository-test/pom.xml
+++ b/repository-test/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/repository-ydb-common/pom.xml b/repository-ydb-common/pom.xml
index 6d70fb81..0f0c839f 100644
--- a/repository-ydb-common/pom.xml
+++ b/repository-ydb-common/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/repository-ydb-v1/pom.xml b/repository-ydb-v1/pom.xml
index c085a4cb..03b53b92 100644
--- a/repository-ydb-v1/pom.xml
+++ b/repository-ydb-v1/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/repository-ydb-v2/pom.xml b/repository-ydb-v2/pom.xml
index ffe46968..1a1e343c 100644
--- a/repository-ydb-v2/pom.xml
+++ b/repository-ydb-v2/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
@@ -104,7 +104,6 @@
tech.ydb.yoj
yoj-repository-test
- 1.0.3-SNAPSHOT
test
diff --git a/repository/pom.xml b/repository/pom.xml
index 31c37e96..f92470f2 100644
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/util/pom.xml b/util/pom.xml
index 50792561..b845942c 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -10,7 +10,7 @@
tech.ydb.yoj
yoj-parent
- 1.0.3-SNAPSHOT
+ 1.1.0-SNAPSHOT
../pom.xml