Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Play2 로 웹 개발
- Akka
- 파이썬
- akka 강좌
- 스위프트
- 이더리움
- play 강좌
- hyperledger fabric
- 스칼라
- Golang
- Hyperledger fabric gossip protocol
- Actor
- 하이브리드앱
- 엔터프라이즈 블록체인
- 파이썬 머신러닝
- Play2
- 파이썬 강좌
- 그라파나
- 파이썬 데이터분석
- 하이퍼레저 패브릭
- play2 강좌
- 플레이프레임워크
- 파이썬 동시성
- 스칼라 동시성
- 스칼라 강좌
- 블록체인
- CORDA
- 주키퍼
- 안드로이드 웹뷰
- Adapter 패턴
Archives
- Today
- Total
HAMA 블로그
[코틀린 코딩 습작] Annotation & Reflection 본문
Dynamic Proxy & Reflection 1
class Tuple3 (val name:String, val age: Int, val rate: Double){
fun size(): Int {
return 3
}
fun getValue(index: Int): Any?{
return when(index) {
0 -> name
1 -> age
2 -> rate
else -> null
}
}
}
class RemoteService{
fun action(req: Any?): Tuple3 {
//do something
return Tuple3("tom", 1, 1.2)
}
}
///
data class Row(val name: String, val age: Int, val rate: Double)
interface Table {
fun getRow1(req: String): Row
fun getRow2(req: String): List<String>
}
class TableHandler: InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
val methodName = method?.name
val service = RemoteService()
if(methodName == "getRow1"){
val returns = service.action(args)
return cast(returns, method.genericReturnType)
}
return null
}
fun cast (value : Any?, typeClass: Type): Any?{
if(value?.let{value::class.java} == typeClass){
return value
}
return when{
value is Tuple3 -> {
Reflection.createKotlinClass(typeClass as Class<*>).primaryConstructor
?.takeIf{it.parameters.size == value.size() }
?.let { it.call(*it.parameters.mapIndexed{ i, parameter -> cast(value.getValue(i), parameter.type.javaType) }.toTypedArray())}
?:value
}
else -> when{
typeClass == Void.TYPE -> null
typeClass == Int::class.java -> when (value){
is Long -> value.toInt()
else -> value
}
typeClass == Double::class.java -> when(value) {
is Int -> value.toDouble()
else -> value
}
else -> value
}
}
}
}
fun main() {
val table = Proxy.newProxyInstance(Table::class.java.classLoader, arrayOf(Table::class.java), TableHandler()) as Table
println(table.getRow1("1"))
}
Dynamic Proxy & Reflection 2
import java.lang.reflect.*
import kotlin.jvm.internal.Reflection
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.javaType
data class Tuple(val name: String, val age: Int, val rate: Double){
fun size(): Int{
return 3
}
fun get(index: Int): Any? {
return when(index) {
0 -> name
1 -> age
2 -> rate
else -> null
}
}
}
class RemoteService() {
fun getRow1(req: Request): Tuple{
//do somthing
println("remote call : ${req.method} ")
println("remote received : ${req.param} ")
return Tuple("hama",22,0.5)
}
fun getRow2(req: Request): Array<String>{
//do somthing
println("remote call : ${req.method} ")
println("remote received : ${req.param} ")
return arrayOf("hama","22","0.5")
}
}
///////////
data class Request(val method: String, val param: Any?)
data class Row1(val name: String, val age: Int, val rate: Double)
interface Table {
fun getRow1(key: String): Row1
fun getRow2(key: String): List<String>
}
class TableHandler : InvocationHandler {
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
val methodName = method.name
return if (method.declaringClass.isInterface) {
val req = Request(methodName, args)
val returns = RemoteService().getRow2(req)
return cast(returns, method.genericReturnType)
} else {
method.invoke(this, *(args ?: emptyArray()))
}
}
fun cast(value: Any?, typeClass: Type): Any? {
if (value?.let { it::class.java } == typeClass) {
return value
}
fun Type.isCollection(): Boolean {
return when (this) {
is ParameterizedType -> (this.rawType as? Class<*>)?.let { Collection::class.java.isAssignableFrom(it) }
?: false
is Class<*> -> Collection::class.java.isAssignableFrom(this)
else -> false
}
}
return when {
value is Tuple -> {
Reflection.createKotlinClass(typeClass as Class<*>).primaryConstructor
?.takeIf { it.parameters.size == value.size() }
?.let {
it.call(*it.parameters.mapIndexed { i, parameter ->
cast(
value.get(i),
parameter.type.javaType
)
}.toTypedArray())
}
?: value
}
value?.let { it::class.java.isArray } ?: false -> {
when {
typeClass.isCollection() -> (value as Array<*>)
.map { element ->
cast(
element,
(typeClass as? ParameterizedType)?.actualTypeArguments?.let { argument -> argument[0] }!!
)
}
.toList()
.also { println(it) }
else ->
Reflection.createKotlinClass(typeClass as Class<*>).primaryConstructor
.also { println(it) }
?.let { it.call(value) }
?: value
}
}
else -> when {
typeClass == Void.TYPE -> null
typeClass == Int::class.java -> when (value) {
is Long -> value.toInt()
else -> value
}
typeClass == Double::class.java -> when (value) {
is Int -> value.toDouble()
else -> value
}
else -> value
}
}
}
}
fun main() {
val loader = Table::class.java.classLoader
val table = Proxy.newProxyInstance(loader, arrayOf(Table::class.java), TableHandler()) as Table
// val result = table.getRow1("12")
// println(result.name)
// println(result.age)
// println(result.rate)
println(table.getRow2("12"))
}
Dynamic Proxy & Reflection & Annotation
import kotlin.jvm.internal.Reflection
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.javaType
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import java.lang.reflect.Type
import kotlin.reflect.KClass
//
object AnnotationUtils {
fun <T : Annotation> findAnnotation(method: Method, annotation: Class<T>) : T? {
return findAnnotation(method.declaringClass, method, annotation)
}
@Suppress("UNCHECKED_CAST")
fun <T : Annotation> findAnnotation(clazz: Class<*>, method: Method, annotation: Class<T>) : T? {
val annotatedMethods = clazz.methods.filter { it.signatureEquals(method) }
.flatMap { it.annotations.filter { a -> annotation.isInstance(a) }.map { a -> a as T } }
return if (annotatedMethods.isEmpty()) {
val children = clazz.interfaces.mapNotNull { findAnnotation(it, method, annotation) }
if (children.isEmpty()) {
clazz.superclass?.let { findAnnotation(it, method, annotation) }
} else {
children.first()
}
} else {
annotatedMethods.first()
}
}
fun <T : Annotation> hasAnnotation(clazz: Class<*>, method: Method, annotation: Class<T>): Boolean {
return null != findAnnotation(clazz, method, annotation)
}
private fun Method.signatureEquals(other: Method): Boolean {
return name == other.name && parameterTypes.contentEquals(other.parameterTypes)
}
}
//
// ============= remote service =============//
data class Tuple(val name: String, val age: Int, val rate: Double){
fun size(): Int{
return 3
}
fun get(index: Int): Any? {
return when(index) {
0 -> name
1 -> age
2 -> rate
else -> null
}
}
}
data class Request(val method: String, val param: Any?)
data class Response( val returns: Any?)
annotation class Converter(val value: KClass<out Action>)
class RemoteService() {
fun getRow(req: Request): Tuple{
//do somthing
println("remote call : ${req.method} ")
println("remote received : ${req.param} ")
return Tuple("hama",22,0.5)
}
}
interface Action {
fun doAction(args: Array<out Any>?): Any?
}
fun CreateAction(method: Method, args : Array<out Any>?): Action {
val converterClazz = AnnotationUtils.findAnnotation(method, Converter::class.java)!!
val obj = converterClazz.value.primaryConstructor?.call()
return obj as Action
}
class ProxyInvocationHandler()
: InvocationHandler {
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
val methodName = method.name
return if (method.declaringClass.isInterface) {
val action = CreateAction(method, args)
val req = Request(methodName, action.doAction(args))
val remote = RemoteService()
val returns = remote.getRow(req)
return cast(returns, method.genericReturnType)
} else {
(args.let { method.invoke(this, *(args ?: emptyArray())) } ?: method.invoke(this))
}
}
fun cast( value : Any? , typeClass: Type): Any? {
if (value?.let { it::class.java } == typeClass) {
return value
}
return when {
value is Tuple -> {
Reflection.createKotlinClass(typeClass as Class<*>).primaryConstructor
?.takeIf { it.parameters.size == value.size() }
?.let { it.call(*it.parameters.mapIndexed { i, parameter -> cast(value.get(i) , parameter.type.javaType) }.toTypedArray()) }
?:value
}
else -> when {
typeClass == Void.TYPE -> null
typeClass == Int::class.java -> when (value) {
is Long -> value.toInt()
else -> value
}
typeClass == Double::class.java -> when (value) {
is Int -> value.toDouble()
else -> value
}
else -> value
}
}
}
}
data class DataTableTupleRow(val name : String, val age: Int, val rate : Double)
interface Table {
fun getRow(param : String): DataTableTupleRow
}
interface DataTable: Table {
@Converter(DataConvertor::class)
override fun getRow(param : String): DataTableTupleRow
class DataConvertor : Action {
override fun doAction(args: Array<out Any>?): Any? {
val arg = args?.get(0)
return (arg as String).toInt()
}
}
}
fun main() {
val loader = DataTable::class.java.classLoader
val handler = ProxyInvocationHandler()
val table = Proxy.newProxyInstance(loader, arrayOf(DataTable::class.java) , handler) as Table
val result = table.getRow("12")
println(result)
}
진행중..
'Kotlin' 카테고리의 다른 글
[코틀린 코딩 습작] Visitor (0) | 2021.05.20 |
---|---|
[코틀린 코딩 습작] Intercepting Fillter (0) | 2021.05.15 |
[코틀린 코딩 습작] Future (0) | 2021.05.15 |
[코틀린 코딩 습작] Double Dispatch (0) | 2021.05.15 |
[코틀린 코딩 습작] recursive types bound (0) | 2021.05.11 |
Comments