jeudi 19 décembre 2019

Object conversion using generics

I do have an object conversion task that scrumbles my mind ;) Lets assume, I have three (or more) formats of a business objects

class MapA { /*some implementation */ }

class MapB { /*some implementation */ }

class MapC { /*some implementation */ }

In addition I have a "super object" that is stored in a data base and contains the superset of all properties of MapA, MapB and MapC.

class SuperMap { /* all implemented properties from all maps */ }

I now need to be able to convert from and to any map type. So My idea was to specify a specific Converter interface that converts a specific map to the super map.

interface Converter<F>{

    fun convertFrom(map: F): SuperMap
    fun convertTo(map: SuperMap): F

}

The owner of the several map types then only have to implement map type <-> super map

class MapAConverter: Converter<MapA> {

    override fun convertFrom(map: MapA): SuperMap {
        return SuperMap()
    }

    override fun convertTo(map: SuperMap): MapA {
        return MapA()
    }
}

/* more converters */

Finally, I thought about a service then does the following: If the user wants to convert MapA to MapC, the service internally converts MapA -> SuperMap -> MapC, ... that way I do not have to code out all possible combinations ...

class ConverterService
{
    private val converters = mutableMapOf<KType, Converter<T>>()

    fun <T>register(converter: Converter<T>){
        this.converters[T::class] = converter
    }

    fun <F, T>Convert(map: F): T{

        // F ... from map
        val conv1 = converters[F::class]
        if (conv1 == null)
            throw Exception("No converter for this type of map")

        // convert to super class
        val sc = conv1.convertFrom(map)

        // T ... to map
        val conv2 = converters[T::class]
        if(conv2 == null){
            throw Exception("No converter for this type of map")
        }

        // convert to desirect class
        return conv2.convertFrom(sc) as T
    }
}

But that doesnt work...

  1. The converters hashmap does not know about T

  2. val conv1 = converters[F::class] tells me that F::class needs to be reifeid and wants to make Convert to an inline function. If I do either, it gets even more complicated ...

My implementation idea was as follows:

fun main() {

    // register some converters
    var cs = ConverterService()
    cs.register(MapAConverter())
    cs.register(MapBConverter())
    cs.register(MapCConverter())

    // input is map a
    val ma = MapA()

    // i want map c
    val mc = cs.Convert<MapA, MapC>(ma)

}

Can that be achieved somehow? I am happy for any hint/ suggestion.

Thank you!

Aucun commentaire:

Enregistrer un commentaire