Skip to content

Commit

Permalink
FIX: KotlinDataClassComponent.getType() returned invalid raw type
Browse files Browse the repository at this point in the history
  • Loading branch information
nvamelichev committed Feb 1, 2024
1 parent 51c3007 commit d6dd53e
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package tech.ydb.yoj.databind.schema.reflect;

import com.google.common.reflect.TypeToken;
import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KCallable;
import kotlin.reflect.KClass;
import kotlin.reflect.jvm.KCallablesJvm;
import kotlin.reflect.jvm.ReflectJvmMapping;
import tech.ydb.yoj.databind.FieldValueType;
Expand All @@ -22,7 +24,7 @@ public final class KotlinDataClassComponent implements ReflectField {
private final Class<?> type;
private final FieldValueType valueType;
private final Column column;

private final ReflectType<?> reflectType;

public KotlinDataClassComponent(Reflector reflector, String name, KCallable<?> callable) {
Expand All @@ -33,7 +35,15 @@ public KotlinDataClassComponent(Reflector reflector, String name, KCallable<?> c

var kReturnType = callable.getReturnType();
this.genericType = ReflectJvmMapping.getJavaType(kReturnType);
this.type = JvmClassMappingKt.getJavaClass(kReturnType);

var kClassifier = kReturnType.getClassifier();
if (kClassifier instanceof KClass<?> kClass) {
this.type = JvmClassMappingKt.getJavaClass(kClass);
} else {
// fallback to Guava's TypeToken if kotlin-reflect returns unpredictable results ;-)
this.type = TypeToken.of(genericType).getRawType();
}

this.column = type.getAnnotation(Column.class);
this.valueType = FieldValueType.forJavaType(genericType, column);
this.reflectType = reflector.reflectFieldType(genericType, valueType);
Expand Down
39 changes: 39 additions & 0 deletions repository/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@
<artifactId>simpleclient</artifactId>
</dependency>

<!-- Optional (Kotlin support) -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
Expand Down Expand Up @@ -70,4 +82,31 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<executions>
<execution>
<id>compileTests</id>
<phase>process-test-sources</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/test/java</source>
<source>src/test/resources</source>
<source>src/test/kotlin</source>
<source>target/generated-sources/annotations</source>
</sourceDirs>
<jvmTarget>17</jvmTarget>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tech.ydb.yoj.repository.hybrid;

import java.time.Instant;

public record ChangeMetadata(
ChangeKind kind,
Instant time,
long version
) {
enum ChangeKind {
CREATE,
UPDATE,
DELETE,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tech.ydb.yoj.repository.hybrid;

import java.time.Instant;

public record Chronology(
Instant createdAt,
Instant updatedAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package tech.ydb.yoj.repository.hybrid

import tech.ydb.yoj.repository.db.Entity

data class Account(
private val id: Id,
private val version: Long,
private val chronology: Chronology,
val login: String,
val description: String? = null,
) : Entity<Account> {
override fun getId() = id

data class Id(val value: String) : Entity.Id<Account>

data class Snapshot(
private val id: Id,
private val entity: Account?,
val meta: ChangeMetadata,
) : Entity<Snapshot> {
override fun getId() = id

data class Id(
private val id: Account.Id,
private val version: Long
) : Entity.Id<Snapshot>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package tech.ydb.yoj.repository.hybrid

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import tech.ydb.yoj.repository.db.EntitySchema
import java.time.Instant

/**
* Test for Schema using both Kotlin data classes and JVM records.
*/
class HybridSchemaTest {
@Test
fun testIdFlattening() {
val now = Instant.now()
val account = Account(
id = Account.Id("hahaha"),
version = 1L,
chronology = Chronology(now, now),
login = "logIn",
description = null
)
val accountSnapshot = Account.Snapshot(
id = Account.Snapshot.Id(account.id, 1L),
entity = account,
meta = ChangeMetadata(ChangeMetadata.ChangeKind.CREATE, now, 1L)
)

val schema = EntitySchema.of(Account.Snapshot::class.java)

val flattened = schema.flatten(accountSnapshot)
assertThat(flattened).isEqualTo(mapOf(
"id_id" to "hahaha",
"id_version" to 1L,
"entity_id" to "hahaha",
"entity_version" to 1L,
"entity_chronology_createdAt" to now,
"entity_chronology_updatedAt" to now,
"entity_login" to "logIn",
"meta_kind" to ChangeMetadata.ChangeKind.CREATE,
"meta_time" to now,
"meta_version" to 1L
))
assertThat(schema.newInstance(flattened)).isEqualTo(accountSnapshot)
}
}

0 comments on commit d6dd53e

Please sign in to comment.