Skip to content

Commit 8e207b4

Browse files
authored
Merge pull request #126 from aphu-figure/master
add custom converter
2 parents 8362daf + 18a61db commit 8e207b4

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed
Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,65 @@
11
package com.papsign.ktor.openapigen.parameters.parsers.converters
22

3+
import kotlin.reflect.KClass
34
import kotlin.reflect.KType
45

5-
open class ConverterSelectorFactory(vararg val selectors: ConverterSelector): ConverterFactory {
6+
open class ConverterSelectorFactory(vararg selectors: ConverterSelector): ConverterFactory {
7+
private val converterSelectors = selectors.toMutableList()
8+
69
override fun buildConverter(type: KType): Converter? {
7-
return selectors.find { it.canHandle(type) }?.create(type)
10+
return converterSelectors.find { it.canHandle(type) }?.create(type)
11+
}
12+
13+
fun <T : ConverterSelector> injectConverterBefore(kclass: KClass<T>, converterSelector: ConverterSelector) {
14+
converterSelectors.find { kclass.isInstance(it) }
15+
?.let {
16+
val index = converterSelectors.indexOf(it)
17+
val shiftIndex = if (index <= 0) 0 else index
18+
19+
var previous = converterSelectors.getOrNull(shiftIndex)
20+
converterSelectors[index] = converterSelector
21+
22+
if (shiftIndex == (converterSelectors.size - 1)) {
23+
previous?.let { converterSelectors.add(it) }
24+
} else {
25+
for (i in (index + 1) until converterSelectors.size) {
26+
previous?.let {
27+
val current = converterSelectors[i]
28+
converterSelectors[i] = it
29+
previous = current
30+
}
31+
}
32+
previous?.let { converterSelectors.add(it) }
33+
}
34+
}
35+
?: converterSelectors.add(converterSelector)
36+
}
37+
38+
fun <T : ConverterSelector> injectConverterAfter(kclass: KClass<T>, converterSelector: ConverterSelector) {
39+
converterSelectors.find { kclass.isInstance(it) }
40+
?.let {
41+
val index = converterSelectors.indexOf(it)
42+
43+
if (index == (converterSelectors.size - 1)) {
44+
converterSelectors.add(converterSelector)
45+
} else {
46+
var previous = converterSelectors.getOrNull(index + 1)
47+
converterSelectors[index + 1] = converterSelector
48+
49+
for (i in (index + 2) until converterSelectors.size) {
50+
previous?.let {
51+
val current = converterSelectors[i]
52+
converterSelectors[i] = it
53+
previous = current
54+
}
55+
}
56+
previous?.let { converterSelectors.add(it) }
57+
}
58+
}
59+
?: converterSelectors.add(converterSelector)
60+
}
61+
62+
fun <T : ConverterSelector> removeConverter(kclass: KClass<T>) {
63+
converterSelectors.removeIf { kclass.isInstance(it) }
864
}
965
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.papsign.ktor.openapigen.parameters.parsers.builder.query.form
2+
3+
import com.papsign.ktor.openapigen.parameters.parsers.builders.query.form.FormBuilderFactory
4+
import com.papsign.ktor.openapigen.parameters.parsers.converters.Converter
5+
import com.papsign.ktor.openapigen.parameters.parsers.converters.ConverterSelector
6+
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverter
7+
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverterFactory
8+
import com.papsign.ktor.openapigen.parameters.parsers.testSelector
9+
import com.papsign.ktor.openapigen.parameters.parsers.testSelectorFails
10+
import org.junit.After
11+
import org.junit.Before
12+
import org.junit.Test
13+
import java.time.OffsetDateTime
14+
import java.util.UUID
15+
import kotlin.reflect.KType
16+
import kotlin.reflect.full.createType
17+
18+
class InjectBeforeTest {
19+
@Before
20+
fun before() {
21+
PrimitiveConverterFactory.injectConverterBefore(PrimitiveConverter::class, CustomUuidConverter)
22+
}
23+
24+
@After
25+
fun after() {
26+
PrimitiveConverterFactory.removeConverter(CustomUuidConverter::class)
27+
}
28+
29+
@Test
30+
fun testCustomConverter() {
31+
val uuid = "4a5e1ba7-c6fe-49de-abf9-d94614ea3bb8"
32+
val key = "key"
33+
val expected = UUID.fromString(uuid)
34+
val parse = mapOf(
35+
key to listOf(uuid)
36+
)
37+
FormBuilderFactory.testSelector(expected, key, parse, true)
38+
FormBuilderFactory.testSelectorFails<UUID>(key, mapOf(key to listOf("not uuid")), true)
39+
}
40+
}
41+
42+
class InjectAfterAndRemoveTest {
43+
@Before
44+
fun before() {
45+
PrimitiveConverterFactory.injectConverterAfter(PrimitiveConverter::class, AnyToBooleanConverter)
46+
PrimitiveConverterFactory.removeConverter(PrimitiveConverter::class)
47+
}
48+
49+
@After
50+
fun after() {
51+
PrimitiveConverterFactory.injectConverterBefore(AnyToBooleanConverter::class, PrimitiveConverter)
52+
PrimitiveConverterFactory.removeConverter(AnyToBooleanConverter::class)
53+
}
54+
55+
@Test
56+
fun testConverterRemoval() {
57+
val values = listOf("random", 1, UUID.randomUUID(), OffsetDateTime.now())
58+
59+
values.forEach {
60+
val key = "key"
61+
val expected = true
62+
val parse = mapOf(
63+
key to listOf(it.toString())
64+
)
65+
66+
FormBuilderFactory.testSelector(expected, key, parse, true)
67+
}
68+
}
69+
}
70+
71+
private object AnyToBooleanConverter : ConverterSelector, Converter {
72+
override fun convert(value: String): Any = true
73+
74+
override fun canHandle(type: KType): Boolean = true
75+
76+
override fun create(type: KType): Converter = this
77+
}
78+
79+
private object CustomUuidConverter : ConverterSelector, Converter {
80+
override fun convert(value: String): Any = UUID.fromString(value)
81+
82+
override fun canHandle(type: KType): Boolean = type == UUID::class.createType()
83+
84+
override fun create(type: KType): Converter =
85+
if (canHandle(type)) this
86+
else throw RuntimeException("Cannot create converter that can handle $type")
87+
}

0 commit comments

Comments
 (0)