Last active
August 29, 2015 14:05
-
-
Save fancellu/969386f6251107c5a050 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package playpen | |
object CaseMapApp extends App { | |
import caseMapper.CaseMapper._ | |
case class Address(firstLine:String, postcode:String, country:String) | |
case class Person(name: String, age: Int, address:Address) | |
val here=Address("26 Duncoding","KT17 4LX","UK") | |
val dino = Person("Dino", 47,here) | |
println("dino="+dino) | |
val dinoMap=toMap(dino) | |
println(s"dinoMap=$dinoMap") | |
println | |
val addrMap=Map("firstLine"->"18 milo way","postcode"->"KT18 4AA","country"->"UK") | |
val miloAddr=fromMap[Address](addrMap) | |
println(s"miloAddr=$miloAddr") | |
val miloMap=Map("name" -> "Milo", "age" -> 4,"address"->miloAddr) | |
println(s"miloMap=$miloMap") | |
println("milo="+fromMap[Person](miloMap)) | |
println | |
val dinoRoundtrip=fromMap[Person](dinoMap) | |
println("dino roundtrip="+dinoRoundtrip) | |
println(dino==dinoRoundtrip)) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package playpen | |
object CaseMapApp2 extends App { | |
import com.felstar.caseMapper.CaseMapper._ | |
case class Address(firstLine:String, postcode:String, country:String) | |
case class Person(name: String, age: Int, homeAddress:Address,workAddress:Address) | |
val here=Address("26 Duncoding","KT17 4LX","UK") | |
val work=Address("Canary Wharf","E17","UK") | |
val dino = Person("Dino", 47,here,work) | |
println(s"dino=$dino") | |
val dinoMap=toMap2(dino) | |
println(s"dinoMap=$dinoMap") | |
println | |
val dinoRoundtrip=fromMap2[Person](dinoMap) | |
println(s"Dino roundtrip=$dinoRoundtrip") | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package playpen | |
object CaseMapApp3 extends App { | |
import com.felstar.caseMapper.CaseMapper._ | |
case class Address(firstLine:String, postcode:String, country:String) | |
case class Person(name: String, age: Int, homeAddress:Address,workAddress:Address) | |
case class Marriage(person1:Person, person2:Person) | |
val here=Address("26 Duncoding","KT17 4LX","UK") | |
val work=Address("Canary Wharf","E17","UK") | |
val dino = Person("Dino", 47,here,work) | |
val jenny = Person("Jenny", 45,here,here) | |
val marriage=Marriage(dino,jenny) | |
println(s"marriage=$marriage") | |
val marriageMap=toMap2(marriage) | |
println(s"marriageMap=$marriageMap") | |
println | |
val marriageRoundtrip=fromMap2[Marriage](marriageMap) | |
println(s"Marriage roundtrip=$marriageRoundtrip") | |
println(marriage==marriageRoundtrip) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.felstar.caseMapper | |
import scala.language.experimental.macros | |
import scala.reflect.macros.blackbox.Context | |
// For Scala 2.11.x and the ever changing macro APIs! | |
object CaseMapper { | |
type StringAnyMap = scala.collection.Map[String, Any] | |
trait Mappable[T] { | |
def toMap(cas: T): StringAnyMap | |
def toMap2(cas: T): StringAnyMap | |
def fromMap(map: StringAnyMap): T | |
def fromMap2(map: StringAnyMap): T | |
} | |
implicit def toMappable[T]: Mappable[T] = macro CaseMapperMacros.toMappable[T] | |
def toMap[T: Mappable](cas: T) = implicitly[Mappable[T]].toMap(cas) | |
def toMap2[T: Mappable](cas: T) = implicitly[Mappable[T]].toMap2(cas) // this recurses, so case classes also expand to map, CaseMapApp2.scala | |
def fromMap[T: Mappable](map: StringAnyMap) = implicitly[Mappable[T]].fromMap(map) | |
def fromMap2[T: Mappable](map: StringAnyMap) = implicitly[Mappable[T]].fromMap2(map) | |
} | |
private class CaseMapperMacros(val c: Context) { | |
import c.universe._ | |
def toMappable[T: c.WeakTypeTag] = { | |
val tpe = weakTypeOf[T] | |
tpe.normalize.typeSymbol.asClass.isCaseClass | |
val fields = tpe.decls.collectFirst { | |
case m: MethodSymbol if m.isPrimaryConstructor => m | |
}.get.paramLists.head | |
val (pairs, values) = fields.map { field => | |
val name = field.name.toTermName | |
val decodedAsString = name.decodedName.toString | |
val retType = tpe.decl(name).typeSignature | |
// note on fromMap, we don't guard against class cast exception | |
// up to you if you want another policy | |
(q"$decodedAsString->cas.$name", q"map($decodedAsString).asInstanceOf[$retType]") | |
}.unzip | |
val (pairs2, values2) = fields.map { field => | |
val name = field.name.toTermName | |
val decodedAsString = name.decodedName.toString | |
val retType = tpe.decl(name).typeSignature | |
val typeSymbol=retType.typeSymbol | |
if (typeSymbol.asClass.isCaseClass) | |
(q"$decodedAsString->com.felstar.caseMapper.CaseMapper.toMap2(cas.$name)",q"com.felstar.caseMapper.CaseMapper.fromMap2[$retType](map($decodedAsString).asInstanceOf[StringAnyMap])") | |
else (q"$decodedAsString->cas.$name",q"map($decodedAsString).asInstanceOf[$retType]") | |
}.unzip | |
val companionClass = tpe.typeSymbol.companion | |
q""" | |
new Mappable[$tpe] { | |
def toMap(cas: $tpe)=Map(..$pairs) | |
def toMap2(cas: $tpe)=Map(..$pairs2) | |
def fromMap(map: StringAnyMap): $tpe = $companionClass(..$values) | |
def fromMap2(map: StringAnyMap): $tpe = $companionClass(..$values2) | |
} | |
""" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dino=Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK)) | |
dinoMap=Map(name -> Dino, age -> 47, address -> Address(26 Duncoding,KT17 4LX,UK)) | |
miloAddr=Address(18 milo way,KT18 4AA,UK) | |
miloMap=Map(name -> Milo, age -> 4, address -> Address(18 milo way,KT18 4AA,UK)) | |
milo=Person(Milo,4,Address(18 milo way,KT18 4AA,UK)) | |
dino roundtrip=Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK)) | |
true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dino=Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK),Address(Canary Wharf,E17,UK)) | |
dinoMap=Map(name -> Dino, age -> 47, homeAddress -> Map(firstLine -> 26 Duncoding, postcode -> KT17 4LX, country -> UK), workAddress -> Map(firstLine -> Canary Wharf, postcode -> E17, country -> UK)) | |
Dino roundtrip=Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK),Address(Canary Wharf,E17,UK)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
marriage=Marriage(Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK),Address(Canary Wharf,E17,UK)),Person(Jenny,45,Address(26 Duncoding,KT17 4LX,UK),Address(26 Duncoding,KT17 4LX,UK))) | |
marriageMap=Map(person1 -> Map(name -> Dino, age -> 47, homeAddress -> Map(firstLine -> 26 Duncoding, postcode -> KT17 4LX, country -> UK), workAddress -> Map(firstLine -> Canary Wharf, postcode -> E17, country -> UK)), person2 -> Map(name -> Jenny, age -> 45, homeAddress -> Map(firstLine -> 26 Duncoding, postcode -> KT17 4LX, country -> UK), workAddress -> Map(firstLine -> 26 Duncoding, postcode -> KT17 4LX, country -> UK))) | |
Marriage roundtrip=Marriage(Person(Dino,47,Address(26 Duncoding,KT17 4LX,UK),Address(Canary Wharf,E17,UK)),Person(Jenny,45,Address(26 Duncoding,KT17 4LX,UK),Address(26 Duncoding,KT17 4LX,UK))) | |
true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment