Skip to content

Instantly share code, notes, and snippets.

@dotNetTree
Last active June 10, 2022 13:30
Show Gist options
  • Save dotNetTree/6d390aa11d6c7931a9f32cc8796b68d8 to your computer and use it in GitHub Desktop.
Save dotNetTree/6d390aa11d6c7931a9f32cc8796b68d8 to your computer and use it in GitHub Desktop.
Code Spitz 90 - 코틀린 언어편 (2) 과제
// 1. Set도 동작하게
// 2. Map도 동작하게
// 3. inline 함수에 대해 조사한 뒤 최대 반영
// 4. 어떤 클래스에 toJSON():String 메소드가 있다면 그 메소드를 통해 stringify를 하게 하시오
@Target(AnnotationTarget.PROPERTY)
annotation class Ex // 제외할 속성
@Target(AnnotationTarget.PROPERTY)
annotation class Name(val name: String) // json용 별도 이름지정
fun stringify(value: Any): String = StringBuilder().run {
jsonValue(value)
toString()
}
fun StringBuilder.comma() { append(",") }
inline fun StringBuilder.wrap(begin: Char, end: Char, block: StringBuilder.() -> Unit) {
append(begin)
block()
append(end)
}
fun StringBuilder.jsonValue(value: Any?) {
when(value) {
null -> append("null")
is String -> jsonString(value)
is Boolean, is Number -> append("$value")
is Map<*, *> -> jsonMap(value)
is Array<*> -> jsonArray(value)
is Collection<*> -> jsonCollection(value)
else -> {
value::class.members.find { it.name == "toJSON" }.let {
if (it != null) append(it.call(value) as String)
else jsonObject(value)
}
}
}
}
private fun StringBuilder.jsonArray(target: Array<*>) {
wrap('[', ']') {
target.joinTo(this::comma) {
jsonValue(it)
}
}
}
private fun StringBuilder.jsonCollection(target: Collection<*>) {
wrap('[', ']') {
target.joinTo(this::comma) {
jsonValue(it)
}
}
}
private fun StringBuilder.jsonMap(target: Map<*, *>) {
wrap('{', '}') {
target.joinTo(this::comma) { k, v ->
jsonValue(k)
append(":")
jsonValue(v)
}
}
}
private fun StringBuilder.jsonString(v: String) = append(""""${v.replace("\"", "\\\"")}"""")
private fun <T: Any> StringBuilder.jsonObject(target: T) {
wrap('{', '}') {
target::class.members
.filterIsInstance<KProperty<*>>()
.filter { it.findAnnotation<Ex>() == null }
.joinTo(this::comma) {
jsonValue(it.findAnnotation<Name>()?.name ?: it.name)
append(":")
jsonValue(it.getter.call(target))
}
}
}
inline fun <T> Array<T>.joinTo(sep:() -> Unit, transform: (T) -> Unit) {
forEachIndexed { idx, el ->
if (idx != 0) sep()
transform(el)
}
}
inline fun <T> Iterable<T>.joinTo(sep:() -> Unit, transform: (T) -> Unit) {
forEachIndexed { idx, el ->
if (idx != 0) sep()
transform(el)
}
}
inline fun <K, T> Map<K, T>.joinTo(sep:() -> Unit, transform: (K, T) -> Unit) {
entries.forEachIndexed { idx, el ->
if (idx != 0) sep()
val (key, value) = el
transform(key, value)
}
}
class Json1(
val a: Int,
val b: String,
val c: List<Int>,
val d: Set<String>,
val e: Map<Any, Any>,
val f: Array<String>) { }
class Json2(@Ex val a: Int, @Name("title") val b: String) {}
class Json3(val e: Map<Any, Any>) {
fun toJSON(): String = """{"name":"kim"} """
}
class Json4() {
fun toJSON(): String = """{"a":3}"""
}
fun main(args: Array<String>) {
println("ready")
println(
stringify(Json1(
a = 3,
b = "abc",
c = arrayListOf(1,2,3),
d = setOf("kkk", "aaa"),
e = mapOf(
"age1" to 10,
"age2" to 20,
"props" to mapOf(
"name" to "kang",
"age" to 42,
"skills" to listOf("swift", "js", "ts", "kotlin", 1)
)
),
f = arrayOf("array", "test")
))
)
println(stringify(Json2(a = 10, b = "abc")))
println(
stringify(Json3(
e = mapOf(
"skills" to listOf("swift", "js", "ts", "kotlin", 1),
"props" to mapOf(
"name" to "kang",
"age" to 42,
"skills" to listOf("swift", "js", "ts", "kotlin", 1)
)
)
))
)
println(stringify(Json4()))
}
/* 출력
ready
{"a":3,"b":"abc","c":[1,2,3],"d":["kkk","aaa"],"e":{"age1":10,"age2":20,"props":{"name":"kang","age":42,"skills":["swift","js","ts","kotlin",1]}},"f":["array","test"]}
{"title":"abc"}
{"name":"kim"}
{"a":3}
*/
@dotNetTree
Copy link
Author

수정하였습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment