@@ -6,77 +6,96 @@ import scala.reflect.macros.blackbox
6
6
7
7
private object EventAdapterMacroFactory {
8
8
9
- private val supportedClassTypes = List (
10
- " scala.Option" ,
11
- " scala.collection.immutable.List" ,
12
- " scala.collection.immutable.Seq" ,
13
- " scala.collection.Seq" ,
14
- " scala.collection.immutable.Set" ,
15
- " scala.collection.immutable.Map" ,
16
- )
9
+ def mappingOf [E ](context : blackbox.Context )(implicit eventTypeTag : context.WeakTypeTag [E ]): context.Expr [BSONDocumentMapping [E ]] = {
10
+ import context .universe ._
11
+ val (imports, implicits) = implicitMappingsFor(context)(eventTypeTag.tpe, noImplicitForMainType = true )
12
+ val code =
13
+ q """
14
+ import reactivemongo.api.bson._
15
+ import org.nullvector._
16
+ .. $imports
17
+ .. $implicits
18
+ """
19
+ // println(code)
20
+ context.Expr [BSONDocumentMapping [E ]](code)
21
+ }
17
22
18
23
def adaptWithTags [E ](context : blackbox.Context )(withManifest : context.Expr [String ], tags : context.Expr [Set [String ]])
19
24
(implicit eventTypeTag : context.WeakTypeTag [E ]): context.Expr [EventAdapter [E ]] = {
20
25
import context .universe ._
21
- buildAdapterExpression(context)(withManifest, q " override def tags(payload: Any) = $tags" )
26
+ buildAdapterExpression(context)(withManifest, q " new EventAdapterMapping( $withManifest , $tags) " )
22
27
}
23
28
24
29
def adaptWithPayload2Tags [E ](context : blackbox.Context )(withManifest : context.Expr [String ], tags : context.Expr [Any => Set [String ]])
25
30
(implicit eventTypeTag : context.WeakTypeTag [E ]): context.Expr [EventAdapter [E ]] = {
26
31
import context .universe ._
27
- buildAdapterExpression(context)(withManifest, q " override def tags(payload: Any) = $tags(payload )" )
32
+ buildAdapterExpression(context)(withManifest, q " new EventAdapterMapping( $withManifest , $tags) " )
28
33
}
29
34
30
35
def adapt [E ](context : blackbox.Context )(withManifest : context.Expr [String ])
31
36
(implicit eventTypeTag : context.WeakTypeTag [E ]): context.Expr [EventAdapter [E ]] = {
32
- buildAdapterExpression(context)(withManifest, context.universe.EmptyTree )
37
+ import context .universe ._
38
+ buildAdapterExpression(context)(withManifest, q " new EventAdapterMapping( $withManifest) " )
33
39
}
34
40
35
41
private def buildAdapterExpression [E ](context : blackbox.Context )
36
42
(withManifest : context.Expr [String ],
37
- tags : context.universe.Tree
43
+ createEventAdapter : context.universe.Tree
38
44
)
39
45
(implicit eventTypeTag : context.WeakTypeTag [E ]): context.Expr [EventAdapter [E ]] = {
40
46
41
47
import context .universe ._
42
48
val eventType = eventTypeTag.tpe
43
- val eventAdapterTypeName = TypeName (eventType.toString + " EventAdapter" )
44
- val handlers : Seq [context.Tree ] = implicitMappingsFor(context)(eventType)
49
+ val (imports, handlers) = implicitMappingsFor(context)(eventType, noImplicitForMainType = false )
45
50
val code =
46
51
q """
47
- import reactivemongo.api.bson._
48
- class $eventAdapterTypeName extends org.nullvector.EventAdapter[ $eventType]{
49
- val manifest: String = $withManifest
50
- .. $handlers
51
- override def payloadToBson(payload: $eventType): BSONDocument = BSON.writeDocument(payload).get
52
- override def bsonToPayload(doc: BSONDocument): $eventType = BSON.readDocument[ $eventType](doc).get
53
- $tags
54
- }
55
- new $eventAdapterTypeName
56
- """
57
- // println(code)
52
+ import reactivemongo.api.bson._
53
+ import org.nullvector._
54
+ .. $imports
55
+ .. $handlers
56
+ $createEventAdapter
57
+ """
58
+ // println(code)hhh
58
59
context.Expr [EventAdapter [E ]](code)
59
60
}
60
61
61
62
private def implicitMappingsFor (context : blackbox.Context )
62
- (eventType : context.universe.Type ,
63
- ): List [context.universe. Tree ] = {
63
+ (eventType : context.universe.Type , noImplicitForMainType : Boolean = false
64
+ ): ( Set [context. Tree ], List [context.Tree ]) = {
64
65
import context .universe ._
65
66
66
67
val bsonWrtterType = context.typeOf[BSONWriter [_]]
67
68
val bsonReaderType = context.typeOf[BSONReader [_]]
68
69
69
70
val caseClassTypes = extractCaseTypes(context)(eventType).toList.reverse.distinct
70
71
71
- caseClassTypes.collect {
72
- case caseType if context.inferImplicitValue(appliedType(bsonWrtterType, caseType)).isEmpty &&
73
- context.inferImplicitValue(appliedType(bsonReaderType, caseType)).isEmpty =>
74
- q " private implicit val ${TermName (context.freshName())}: BSONDocumentHandler[ $caseType] = Macros.handler[ $caseType] "
72
+ @ scala.annotation.tailrec
73
+ def findPackage (symbol : Symbol ): Option [String ] = {
74
+ symbol match {
75
+ case NoSymbol => None
76
+ case _ if ! symbol.isPackage => findPackage(symbol.owner)
77
+ case _ if symbol.isPackage => Some (symbol.fullName)
78
+ case _ => None
79
+ }
80
+ }
81
+
82
+ val (mappedTypes, mappingCode) = caseClassTypes.collect {
83
+ case caseType if noImplicitForMainType & caseType =:= eventType =>
84
+ caseType -> q " Macros.handler[ $caseType] "
85
+ case caseType if context.inferImplicitValue(appliedType(bsonWrtterType, caseType)).isEmpty && context.inferImplicitValue(appliedType(bsonReaderType, caseType)).isEmpty =>
86
+ caseType -> q " private implicit val ${TermName (context.freshName())}: BSONDocumentHandler[ ${caseType}] = Macros.handler[ ${caseType}] "
75
87
case caseType if ! context.inferImplicitValue(appliedType(bsonReaderType, caseType)).isEmpty =>
76
- q " private implicit val ${TermName (context.freshName())}: BSONWriter[ $caseType] = Macros.handler[ $caseType] "
88
+ caseType -> q " private implicit val ${TermName (context.freshName())}: BSONWriter[ ${ caseType} ] = Macros.handler[ ${ caseType} ] "
77
89
case caseType if ! context.inferImplicitValue(appliedType(bsonWrtterType, caseType)).isEmpty =>
78
- q " private implicit val ${TermName (context.freshName())}: BSONReader[ $caseType] = Macros.handler[ $caseType] "
79
- }
90
+ caseType -> q " private implicit val ${TermName (context.freshName())}: BSONReader[ ${caseType}] = Macros.handler[ ${caseType}] "
91
+ }.unzip
92
+ (
93
+ mappedTypes
94
+ .flatMap(tpe => findPackage(tpe.typeSymbol))
95
+ .toSet
96
+ .map((packageName : String ) => context.parse(s " import $packageName._ " )),
97
+ mappingCode
98
+ )
80
99
}
81
100
82
101
private def extractCaseTypes (context : blackbox.Context )
@@ -85,11 +104,11 @@ private object EventAdapterMacroFactory {
85
104
86
105
def isSupprtedTrait (aTypeClass : ClassSymbol ) = aTypeClass.isTrait && aTypeClass.isSealed && ! aTypeClass.fullName.startsWith(" scala" )
87
106
88
- def extaracCaseClassesFromSupportedTypeClasses (classType : Type ): List [Type ] = {
89
- if (supportedClassTypes.contains(classType.typeSymbol.fullName)) classType.typeArgs.collect {
107
+ def extaracCaseClassesFromTypeArgs (classType : Type ): List [Type ] = {
108
+ classType.typeArgs.collect {
90
109
case argType if argType.typeSymbol.asClass.isCaseClass => List (classType, argType)
91
- case t => extaracCaseClassesFromSupportedTypeClasses (t)
92
- }.flatten else Nil
110
+ case t => extaracCaseClassesFromTypeArgs (t)
111
+ }.flatten
93
112
}
94
113
95
114
if (caseType.typeSymbol.asClass.isCaseClass) {
@@ -98,7 +117,7 @@ private object EventAdapterMacroFactory {
98
117
.collect { case method : MethodSymbol if method.isCaseAccessor => method.returnType }
99
118
.collect {
100
119
case aType if aType.typeSymbol.asClass.isCaseClass || isSupprtedTrait(aType.typeSymbol.asClass) => List (extractCaseTypes(context)(aType))
101
- case aType => extaracCaseClassesFromSupportedTypeClasses (aType).map(arg => extractCaseTypes(context)(arg))
120
+ case aType => extaracCaseClassesFromTypeArgs (aType).map(arg => extractCaseTypes(context)(arg))
102
121
}.flatten
103
122
)
104
123
}
0 commit comments