Skip to content

Commit

Permalink
Merge pull request #126 from aphu-figure/master
Browse files Browse the repository at this point in the history
add custom converter
  • Loading branch information
Wicpar authored Jun 18, 2022
2 parents 8362daf + 18a61db commit 8e207b4
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,65 @@
package com.papsign.ktor.openapigen.parameters.parsers.converters

import kotlin.reflect.KClass
import kotlin.reflect.KType

open class ConverterSelectorFactory(vararg val selectors: ConverterSelector): ConverterFactory {
open class ConverterSelectorFactory(vararg selectors: ConverterSelector): ConverterFactory {
private val converterSelectors = selectors.toMutableList()

override fun buildConverter(type: KType): Converter? {
return selectors.find { it.canHandle(type) }?.create(type)
return converterSelectors.find { it.canHandle(type) }?.create(type)
}

fun <T : ConverterSelector> injectConverterBefore(kclass: KClass<T>, converterSelector: ConverterSelector) {
converterSelectors.find { kclass.isInstance(it) }
?.let {
val index = converterSelectors.indexOf(it)
val shiftIndex = if (index <= 0) 0 else index

var previous = converterSelectors.getOrNull(shiftIndex)
converterSelectors[index] = converterSelector

if (shiftIndex == (converterSelectors.size - 1)) {
previous?.let { converterSelectors.add(it) }
} else {
for (i in (index + 1) until converterSelectors.size) {
previous?.let {
val current = converterSelectors[i]
converterSelectors[i] = it
previous = current
}
}
previous?.let { converterSelectors.add(it) }
}
}
?: converterSelectors.add(converterSelector)
}

fun <T : ConverterSelector> injectConverterAfter(kclass: KClass<T>, converterSelector: ConverterSelector) {
converterSelectors.find { kclass.isInstance(it) }
?.let {
val index = converterSelectors.indexOf(it)

if (index == (converterSelectors.size - 1)) {
converterSelectors.add(converterSelector)
} else {
var previous = converterSelectors.getOrNull(index + 1)
converterSelectors[index + 1] = converterSelector

for (i in (index + 2) until converterSelectors.size) {
previous?.let {
val current = converterSelectors[i]
converterSelectors[i] = it
previous = current
}
}
previous?.let { converterSelectors.add(it) }
}
}
?: converterSelectors.add(converterSelector)
}

fun <T : ConverterSelector> removeConverter(kclass: KClass<T>) {
converterSelectors.removeIf { kclass.isInstance(it) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.papsign.ktor.openapigen.parameters.parsers.builder.query.form

import com.papsign.ktor.openapigen.parameters.parsers.builders.query.form.FormBuilderFactory
import com.papsign.ktor.openapigen.parameters.parsers.converters.Converter
import com.papsign.ktor.openapigen.parameters.parsers.converters.ConverterSelector
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverter
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverterFactory
import com.papsign.ktor.openapigen.parameters.parsers.testSelector
import com.papsign.ktor.openapigen.parameters.parsers.testSelectorFails
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.time.OffsetDateTime
import java.util.UUID
import kotlin.reflect.KType
import kotlin.reflect.full.createType

class InjectBeforeTest {
@Before
fun before() {
PrimitiveConverterFactory.injectConverterBefore(PrimitiveConverter::class, CustomUuidConverter)
}

@After
fun after() {
PrimitiveConverterFactory.removeConverter(CustomUuidConverter::class)
}

@Test
fun testCustomConverter() {
val uuid = "4a5e1ba7-c6fe-49de-abf9-d94614ea3bb8"
val key = "key"
val expected = UUID.fromString(uuid)
val parse = mapOf(
key to listOf(uuid)
)
FormBuilderFactory.testSelector(expected, key, parse, true)
FormBuilderFactory.testSelectorFails<UUID>(key, mapOf(key to listOf("not uuid")), true)
}
}

class InjectAfterAndRemoveTest {
@Before
fun before() {
PrimitiveConverterFactory.injectConverterAfter(PrimitiveConverter::class, AnyToBooleanConverter)
PrimitiveConverterFactory.removeConverter(PrimitiveConverter::class)
}

@After
fun after() {
PrimitiveConverterFactory.injectConverterBefore(AnyToBooleanConverter::class, PrimitiveConverter)
PrimitiveConverterFactory.removeConverter(AnyToBooleanConverter::class)
}

@Test
fun testConverterRemoval() {
val values = listOf("random", 1, UUID.randomUUID(), OffsetDateTime.now())

values.forEach {
val key = "key"
val expected = true
val parse = mapOf(
key to listOf(it.toString())
)

FormBuilderFactory.testSelector(expected, key, parse, true)
}
}
}

private object AnyToBooleanConverter : ConverterSelector, Converter {
override fun convert(value: String): Any = true

override fun canHandle(type: KType): Boolean = true

override fun create(type: KType): Converter = this
}

private object CustomUuidConverter : ConverterSelector, Converter {
override fun convert(value: String): Any = UUID.fromString(value)

override fun canHandle(type: KType): Boolean = type == UUID::class.createType()

override fun create(type: KType): Converter =
if (canHandle(type)) this
else throw RuntimeException("Cannot create converter that can handle $type")
}

0 comments on commit 8e207b4

Please sign in to comment.