Skip to content

Commit 5456da3

Browse files
author
Adrian Tosca
committed
add annotation-based prefix customization
1 parent b395dff commit 5456da3

File tree

11 files changed

+93
-13
lines changed

11 files changed

+93
-13
lines changed

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# typeid-kotlin
22
![Build Status](https://github.com/aleris/typeid-kotlin/actions/workflows/build-on-push.yml/badge.svg)
3-
![Current Version](https://img.shields.io/badge/Version-0.0.10-blue)
3+
![Current Version](https://img.shields.io/badge/Version-0.0.11-blue)
44

55

66
## A Kotlin implementation of [TypeID](https://github.com/jetpack-io/typeid).
@@ -25,14 +25,14 @@ To use with Maven:
2525
<dependency>
2626
<groupId>earth.adi</groupId>
2727
<artifactId>typeid-kotlin</artifactId>
28-
<version>0.0.10</version>
28+
<version>0.0.11</version>
2929
</dependency>
3030
```
3131

3232
To use via Gradle:
3333

3434
```kotlin
35-
implementation("earth.adi:typeid-kotlin:0.0.10")
35+
implementation("earth.adi:typeid-kotlin:0.0.11")
3636
```
3737

3838

@@ -208,6 +208,29 @@ val typeId = typeId().withCustomPrefix(TypedPrefix<Organization>("org"))
208208
println(typeId.randomId<Organization>()) // prints something like org_01h455vb4pex5vsknk084sn02q
209209
```
210210

211+
Another possibility is to add `TypedPrefix` to the entity instance:
212+
213+
```kotlin
214+
@TypeIdPrefix("cust")
215+
data class Customer(override val id: CustomerId)
216+
```
217+
218+
This can also be useful when you want a different entity interface in a different module. For example:
219+
220+
```kotlin
221+
@TypeIdPrefix("customer")
222+
interface CustomerIdentifiable {
223+
val id: CustomerId
224+
}
225+
226+
typealias CustomerId = Id<out CustomerIdentifiable>
227+
228+
data class Customer(override val id: CustomerId) : CustomerIdentifiable
229+
```
230+
231+
If the `@TypeIdPrefix` is present TypeId will use that.
232+
Note that the prefixes registered trough the `TypeId` instance will take precedence over the ones defined in the entity.
233+
211234

212235
### Customizing the UUID generator
213236

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ plugins {
1515

1616
group = "earth.adi"
1717

18-
version = "0.0.10"
18+
version = "0.0.11"
1919

2020
repositories { mavenCentral() }
2121

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package earth.adi.typeid.annotations
2+
3+
@Target(AnnotationTarget.CLASS)
4+
@Retention(AnnotationRetention.RUNTIME)
5+
@MustBeDocumented
6+
annotation class TypeIdPrefix(val value: String)

src/main/kotlin/earth/adi/typeid/codec/Factory.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import earth.adi.typeid.Id
55
import earth.adi.typeid.RawId
66
import earth.adi.typeid.TypedPrefix
77
import earth.adi.typeid.Validated
8+
import earth.adi.typeid.annotations.TypeIdPrefix
89
import java.util.*
910

1011
/**
@@ -181,6 +182,13 @@ class Factory {
181182
}
182183

183184
private fun <TEntity> defaultPrefix(entityType: Class<out TEntity>): TypedPrefix<out TEntity> {
185+
entityType.annotations
186+
.find { it is TypeIdPrefix }
187+
?.let {
188+
val typeIdPrefix = (it as TypeIdPrefix).value
189+
Codec.requireValidPrefix(typeIdPrefix)
190+
return TypedPrefix(typeIdPrefix)
191+
}
184192
return TypedPrefix(entityType.simpleName.lowercase())
185193
}
186194
}

src/test/kotlin/earth/adi/typeid/TypeIdTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package earth.adi.typeid
22

3+
import earth.adi.typeid.testentities.CustomerIdentifiable
4+
import earth.adi.typeid.testentities.Organization
5+
import earth.adi.typeid.testentities.User
6+
import earth.adi.typeid.testentities.UserRepository
37
import java.util.*
48
import org.assertj.core.api.Assertions.assertThat
59
import org.assertj.core.api.Assertions.assertThatThrownBy
@@ -129,6 +133,12 @@ class TypeIdTest {
129133
assertThat(organizationId.toString()).startsWith("org_")
130134
}
131135

136+
@Test
137+
fun `randomId with prefix customization in annotation`() {
138+
val customerId = typeId.randomId<CustomerIdentifiable>() // customer_01hy0sk45qfmdsdme1j703yjet
139+
assertThat(customerId.toString()).startsWith("customer_")
140+
}
141+
132142
@Test
133143
fun `tryParse valid`() {
134144
val organizationId = typeId.randomId<Organization>()

src/test/kotlin/earth/adi/typeid/ValidatedTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package earth.adi.typeid
22

3+
import earth.adi.typeid.testentities.User
4+
import earth.adi.typeid.testentities.UserId
35
import java.util.concurrent.atomic.AtomicBoolean
46
import org.assertj.core.api.Assertions.assertThat
57
import org.junit.jupiter.api.Test

src/test/kotlin/earth/adi/typeid/jackson/JacksonJsonTest.kt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.PropertyName
66
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
77
import com.fasterxml.jackson.module.kotlin.readValue
88
import earth.adi.typeid.*
9+
import earth.adi.typeid.testentities.*
910
import java.io.ByteArrayOutputStream
1011
import org.assertj.core.api.Assertions.assertThat
1112
import org.junit.jupiter.api.Test
@@ -30,14 +31,15 @@ class JacksonJsonTest {
3031

3132
private val objectMapper = jacksonObjectMapper().registerModule(typeId.jacksonModule())
3233

33-
data class JsonUserAndOrganization(
34+
data class EntitiesWithIds(
3435
val user: User,
3536
val organization: Organization,
37+
val customer: Customer,
3638
)
3739

3840
@Test
3941
fun `deserialize from json`() {
40-
val json = objectMapper.readValue<JsonUserAndOrganization>(JSON_USER_AND_ORGANIZATION)
42+
val json = objectMapper.readValue<EntitiesWithIds>(JSON_ENTITIES_WITH_IDS)
4143
assertThat(json.user.id).isEqualTo(typeId.parse<User>("user_01hy0d96sgfx0rh975kqkspchh"))
4244
assertThat(json.organization.id)
4345
.isEqualTo(typeId.parse<Organization>("org_01hy0sk45qfmdsdme1j703yjet"))
@@ -46,17 +48,19 @@ class JacksonJsonTest {
4648
@Test
4749
fun `serialize to json`() {
4850
val json =
49-
JsonUserAndOrganization(
51+
EntitiesWithIds(
5052
User(typeId.parse<User>("user_01hy0d96sgfx0rh975kqkspchh")),
5153
Organization(typeId.parse<Organization>("org_01hy0sk45qfmdsdme1j703yjet")),
54+
Customer(typeId.parse<CustomerIdentifiable>("customer_01hyb7c8a3eyws8s8d037qfr6b")),
5255
)
5356
val writtenJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json)
54-
assertThat(writtenJson).isEqualTo(JSON_USER_AND_ORGANIZATION)
57+
assertThat(writtenJson).isEqualTo(JSON_ENTITIES_WITH_IDS)
5558
}
5659

5760
data class IdsOnly(
5861
@JsonProperty("user_id") val userId: UserId,
5962
@JsonProperty("org_id") val organizationId: OrganizationId,
63+
@JsonProperty("customer_id") val customerId: CustomerId,
6064
)
6165

6266
@Test
@@ -65,6 +69,8 @@ class JacksonJsonTest {
6569
assertThat(json.userId).isEqualTo(typeId.parse<User>("user_01hy0d96sgfx0rh975kqkspchh"))
6670
assertThat(json.organizationId)
6771
.isEqualTo(typeId.parse<Organization>("org_01hy0sk45qfmdsdme1j703yjet"))
72+
assertThat(json.customerId)
73+
.isEqualTo(typeId.parse<CustomerIdentifiable>("customer_01hyb7c8a3eyws8s8d037qfr6b"))
6874
}
6975

7076
@Test
@@ -73,6 +79,7 @@ class JacksonJsonTest {
7379
IdsOnly(
7480
typeId.parse<User>("user_01hy0d96sgfx0rh975kqkspchh"),
7581
typeId.parse<Organization>("org_01hy0sk45qfmdsdme1j703yjet"),
82+
typeId.parse<CustomerIdentifiable>("customer_01hyb7c8a3eyws8s8d037qfr6b"),
7683
)
7784
val writtenJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json)
7885
assertThat(writtenJson).isEqualTo(JSON_IDS_ONLY)
@@ -81,13 +88,15 @@ class JacksonJsonTest {
8188
data class RawIds(
8289
@JsonProperty("user_id") val userId: RawId,
8390
@JsonProperty("org_id") val organizationId: RawId,
91+
@JsonProperty("customer_id") val customerId: RawId,
8492
)
8593

8694
@Test
8795
fun `deserialize raw ids from json`() {
8896
val json = objectMapper.readValue<RawIds>(JSON_IDS_ONLY)
8997
assertThat(json.userId).isEqualTo(typeId.parse("user_01hy0d96sgfx0rh975kqkspchh"))
9098
assertThat(json.organizationId).isEqualTo(typeId.parse("org_01hy0sk45qfmdsdme1j703yjet"))
99+
assertThat(json.customerId).isEqualTo(typeId.parse("customer_01hyb7c8a3eyws8s8d037qfr6b"))
91100
}
92101

93102
@Test
@@ -96,6 +105,7 @@ class JacksonJsonTest {
96105
RawIds(
97106
typeId.parse("user_01hy0d96sgfx0rh975kqkspchh"),
98107
typeId.parse("org_01hy0sk45qfmdsdme1j703yjet"),
108+
typeId.parse("customer_01hyb7c8a3eyws8s8d037qfr6b"),
99109
)
100110
val writtenJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json)
101111
assertThat(writtenJson).isEqualTo(JSON_IDS_ONLY)
@@ -150,14 +160,17 @@ class JacksonJsonTest {
150160
"""
151161
.trimIndent()
152162

153-
private val JSON_USER_AND_ORGANIZATION =
163+
private val JSON_ENTITIES_WITH_IDS =
154164
"""
155165
{
156166
"user" : {
157167
"id" : "user_01hy0d96sgfx0rh975kqkspchh"
158168
},
159169
"organization" : {
160170
"id" : "org_01hy0sk45qfmdsdme1j703yjet"
171+
},
172+
"customer" : {
173+
"id" : "customer_01hyb7c8a3eyws8s8d037qfr6b"
161174
}
162175
}
163176
"""
@@ -167,7 +180,8 @@ class JacksonJsonTest {
167180
"""
168181
{
169182
"user_id" : "user_01hy0d96sgfx0rh975kqkspchh",
170-
"org_id" : "org_01hy0sk45qfmdsdme1j703yjet"
183+
"org_id" : "org_01hy0sk45qfmdsdme1j703yjet",
184+
"customer_id" : "customer_01hyb7c8a3eyws8s8d037qfr6b"
171185
}
172186
"""
173187
.trimIndent()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package earth.adi.typeid.testentities
2+
3+
import earth.adi.typeid.Id
4+
import earth.adi.typeid.annotations.TypeIdPrefix
5+
6+
@TypeIdPrefix("customer")
7+
interface CustomerIdentifiable {
8+
val id: CustomerId
9+
}
10+
11+
typealias CustomerId = Id<out CustomerIdentifiable>
12+
13+
data class Customer(override val id: CustomerId) : CustomerIdentifiable

src/test/kotlin/earth/adi/typeid/OrganizationId.kt renamed to src/test/kotlin/earth/adi/typeid/testentities/OrganizationId.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
package earth.adi.typeid
1+
package earth.adi.typeid.testentities
2+
3+
import earth.adi.typeid.Id
24

35
data class Organization(val id: OrganizationId)
46

src/test/kotlin/earth/adi/typeid/UserId.kt renamed to src/test/kotlin/earth/adi/typeid/testentities/UserId.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
package earth.adi.typeid
1+
package earth.adi.typeid.testentities
2+
3+
import earth.adi.typeid.Id
24

35
data class User(val id: UserId)
46

src/test/kotlin/earth/adi/typeid/UserRepository.kt renamed to src/test/kotlin/earth/adi/typeid/testentities/UserRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package earth.adi.typeid
1+
package earth.adi.typeid.testentities
22

33
class UserRepository {
44
fun get(id: UserId): User {

0 commit comments

Comments
 (0)