@@ -809,8 +809,6 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
809
809
}
810
810
}
811
811
812
- private case class FieldAnnotations (partiallyMappedName : Option [String ], transient : Boolean , stringified : Boolean )
813
-
814
812
private case class DecoderMethodKey (tpe : TypeRepr , isStringified : Boolean , useDiscriminator : Boolean )
815
813
816
814
private case class EncoderMethodKey (tpe : TypeRepr , isStringified : Boolean , discriminatorKeyValue : Option [(String , String )])
@@ -846,15 +844,19 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
846
844
private val unitTpe = defn.UnitClass .typeRef
847
845
private val anyTpe = defn.AnyClass .typeRef
848
846
private val arrayOfAnyTpe = defn.ArrayClass .typeRef.appliedTo(anyTpe)
849
- private val iArrayOfAnyRefTpe = TypeRepr .of[IArray [AnyRef ]]
850
847
private val stringTpe = TypeRepr .of[String ]
848
+ private val optionTpe = TypeRepr .of[Option [? ]]
851
849
private val tupleTpe = TypeRepr .of[Tuple ]
850
+ private val iterableTpe = TypeRepr .of[Iterable [? ]]
851
+ private val iteratorTpe = TypeRepr .of[Iterator [? ]]
852
+ private val arrayTpe = TypeRepr .of[Array [? ]]
853
+ private val iArrayOfAnyRefTpe = TypeRepr .of[IArray [AnyRef ]]
852
854
private val jsonKeyCodecTpe = TypeRepr .of[JsonKeyCodec ]
853
855
private val jsonValueCodecTpe = TypeRepr .of[JsonValueCodec ]
854
856
private val newArray = Select (New (TypeIdent (defn.ArrayClass )), defn.ArrayClass .primaryConstructor)
855
857
private val newArrayOfAny = TypeApply (newArray, List (Inferred (anyTpe)))
856
858
private val fromIArrayMethod = Select .unique(Ref (Symbol .requiredModule(" scala.runtime.TupleXXL" )), " fromIArray" )
857
- private val asInstanceOfMethod = anyTpe.typeSymbol.methodMember (" asInstanceOf" ).head
859
+ private val asInstanceOfMethod = anyTpe.typeSymbol.declaredMethod (" asInstanceOf" ).head
858
860
private val inferredKeyCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonKeyCodec [? ]]]]
859
861
private val inferredValueCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonValueCodec [? ]]]]
860
862
private val inferredOrderings = new mutable.HashMap [TypeRepr , Term ]
@@ -959,17 +961,17 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
959
961
else tpe.typeSymbol.companionModule
960
962
}
961
963
962
- private def isOption (tpe : TypeRepr , types : List [TypeRepr ]): Boolean = tpe <:< TypeRepr .of[ Option [ ? ]] &&
963
- (cfg.skipNestedOptionValues || ! types.headOption.exists(_ <:< TypeRepr .of[ Option [ ? ]] ))
964
+ private def isOption (tpe : TypeRepr , types : List [TypeRepr ]): Boolean = tpe <:< optionTpe &&
965
+ (cfg.skipNestedOptionValues || ! types.headOption.exists(_ <:< optionTpe ))
964
966
965
967
private def isNullable (tpe : TypeRepr ): Boolean = tpe match
966
968
case OrType (left, right) => isNullable(right) || isNullable(left)
967
969
case _ => tpe =:= TypeRepr .of[Null ]
968
970
969
971
private def isIArray (tpe : TypeRepr ): Boolean = tpe.typeSymbol.fullName == " scala.IArray$package$.IArray"
970
972
971
- private def isCollection (tpe : TypeRepr ): Boolean = tpe <:< TypeRepr .of[ Iterable [ ? ]] ||
972
- tpe <:< TypeRepr .of[ Iterator [ ? ]] || tpe <:< TypeRepr .of[ Array [ ? ]] || isIArray(tpe)
973
+ private def isCollection (tpe : TypeRepr ): Boolean =
974
+ tpe <:< iterableTpe || tpe <:< iteratorTpe || tpe <:< arrayTpe || isIArray(tpe)
973
975
974
976
private def isJavaEnum (tpe : TypeRepr ): Boolean = tpe <:< TypeRepr .of[java.lang.Enum [? ]]
975
977
@@ -1121,43 +1123,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
1121
1123
})
1122
1124
1123
1125
private def getClassInfo (tpe : TypeRepr ): ClassInfo = classInfos.getOrElseUpdate(tpe, {
1124
- def hasSupportedAnnotation (m : Symbol ): Boolean = m.annotations.exists { a =>
1125
- val tpe = a.tpe
1126
- tpe =:= TypeRepr .of[named] || tpe =:= TypeRepr .of[transient] || tpe =:= TypeRepr .of[stringified] ||
1127
- (cfg.scalaTransientSupport && tpe =:= TypeRepr .of[scala.transient])
1128
- }
1129
-
1130
1126
def supportedTransientTypeNames : String =
1131
1127
if (cfg.scalaTransientSupport) s " ' ${Type .show[transient]}' (or ' ${Type .show[scala.transient]}') "
1132
1128
else s " ' ${Type .show[transient]}') "
1133
1129
1134
1130
val tpeTypeArgs = typeArgs(tpe)
1135
1131
val tpeClassSym = tpe.classSymbol.getOrElse(fail(s " Expected that ${tpe.show} has classSymbol " ))
1136
1132
val primaryConstructor = tpeClassSym.primaryConstructor
1137
- var annotations = Map .empty[String , FieldAnnotations ]
1138
1133
val caseFields = tpeClassSym.caseFields
1139
- var companionRefAndMembers : (Ref , List [Symbol ]) = null
1140
1134
var fieldMembers : List [Symbol ] = null
1135
+ var companionRefAndClass : (Ref , Symbol ) = null
1141
1136
var methodMembers : List [Symbol ] = null
1142
1137
1143
- tpeClassSym.fieldMembers.foreach {
1144
- case m : Symbol if hasSupportedAnnotation(m) =>
1145
- val name = m.name
1146
- val named = m.annotations.count(_.tpe =:= TypeRepr .of[named])
1147
- if (named > 1 ) fail(s " Duplicated ' ${TypeRepr .of[named].show}' defined for ' $name' of ' ${tpe.show}'. " )
1148
- val trans = m.annotations.count(a => a.tpe =:= TypeRepr .of[transient] ||
1149
- (cfg.scalaTransientSupport && a.tpe =:= TypeRepr .of[scala.transient]))
1150
- if (trans > 1 ) warn(s " Duplicated $supportedTransientTypeNames defined for ' $name' of ' ${tpe.show}'. " )
1151
- val strings = m.annotations.count(_.tpe =:= TypeRepr .of[stringified])
1152
- if (strings > 1 ) warn(s " Duplicated ' ${TypeRepr .of[stringified].show}' defined for ' $name' of ' ${tpe.show}'. " )
1153
- if ((named > 0 || strings > 0 ) && trans > 0 )
1154
- warn(s " Both $supportedTransientTypeNames and ' ${Type .show[named]}' or " +
1155
- s " $supportedTransientTypeNames and ' ${Type .show[stringified]}' defined for ' $name' of ' ${tpe.show}'. " )
1156
- val partiallyMappedName = namedValueOpt(m.annotations.find(_.tpe =:= TypeRepr .of[named]), tpe)
1157
- annotations = annotations.updated(name, new FieldAnnotations (partiallyMappedName, trans > 0 , strings > 0 ))
1158
- case _ =>
1159
- }
1160
-
1161
1138
def createFieldInfos (params : List [Symbol ], typeParams : List [Symbol ], fieldIndex : Boolean => Int ): List [FieldInfo ] = params.map {
1162
1139
var i = 0
1163
1140
symbol =>
@@ -1171,20 +1148,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
1171
1148
case _ : TypeBounds =>
1172
1149
fail(s " Type bounds are not supported for type ' ${tpe.show}' with field type for $name ' ${fieldTpe.show}' " )
1173
1150
case _ =>
1174
- val defaultValue = if (! cfg.requireDefaultFields && symbol.flags.is(Flags .HasDefault )) {
1175
- val dvMemberName = " $lessinit$greater$default$" + i
1176
- if (companionRefAndMembers eq null ) {
1151
+ val defaultValue = if (! cfg.requireDefaultFields && symbol.flags.is(Flags .HasDefault )) new Some ({
1152
+ if (companionRefAndClass eq null ) {
1177
1153
val typeSymbol = tpe.typeSymbol
1178
- companionRefAndMembers = (Ref (typeSymbol.companionModule), typeSymbol.companionClass.methodMembers)
1179
- }
1180
- companionRefAndMembers._2.collectFirst { case methodSymbol if methodSymbol.name == dvMemberName =>
1181
- val dvSelectNoTypes = Select (companionRefAndMembers._1, methodSymbol)
1182
- methodSymbol.paramSymss match
1183
- case Nil => dvSelectNoTypes
1184
- case List (params) if params.exists(_.isTypeParam) => TypeApply (dvSelectNoTypes, tpeTypeArgs.map(Inferred (_)))
1185
- case paramss => fail(s " Default method for $name of class ${tpe.show} have a complex parameter list: $paramss" )
1154
+ companionRefAndClass = (Ref (typeSymbol.companionModule), typeSymbol.companionClass)
1186
1155
}
1187
- } else None
1156
+ val methodSymbol = companionRefAndClass._2.declaredMethod(" $lessinit$greater$default$" + i).head
1157
+ val dvSelectNoTypes = Select (companionRefAndClass._1, methodSymbol)
1158
+ methodSymbol.paramSymss match
1159
+ case Nil => dvSelectNoTypes
1160
+ case List (params) if params.exists(_.isTypeParam) => TypeApply (dvSelectNoTypes, tpeTypeArgs.map(Inferred (_)))
1161
+ case paramss => fail(s " Default method for $name of class ${tpe.show} have a complex parameter list: $paramss" )
1162
+ }) else None
1188
1163
val getterOrField = caseFields.find(_.name == name) match
1189
1164
case Some (caseField) => caseField
1190
1165
case _ =>
@@ -1199,10 +1174,31 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
1199
1174
if (! getterOrField.exists || getterOrField.flags.is(Flags .PrivateLocal )) {
1200
1175
fail(s " Getter or field ' $name' of ' ${tpe.show}' is private. It should be defined as 'val' or 'var' in the primary constructor. " )
1201
1176
}
1202
- val annotationOption = annotations.get(name)
1203
- val mappedName = annotationOption.flatMap(_.partiallyMappedName).getOrElse(cfg.fieldNameMapper(name).getOrElse(name))
1204
- val isStringified = annotationOption.exists(_.stringified)
1205
- val isTransient = annotationOption.exists(_.transient)
1177
+ var named : Option [Term ] = None
1178
+ var isStringified : Boolean = false
1179
+ var isTransient : Boolean = false
1180
+ getterOrField.annotations.foreach { annotation =>
1181
+ val aTpe = annotation.tpe
1182
+ if (aTpe =:= TypeRepr .of[named]) {
1183
+ if (named eq None ) named = new Some (annotation)
1184
+ else fail(s " Duplicated ' ${TypeRepr .of[named].show}' defined for ' $name' of ' ${tpe.show}'. " )
1185
+ } else if (aTpe =:= TypeRepr .of[stringified]) {
1186
+ if (isStringified) warn(s " Duplicated ' ${TypeRepr .of[stringified].show}' defined for ' $name' of ' ${tpe.show}'. " )
1187
+ isStringified = true
1188
+ } else if (aTpe =:= TypeRepr .of[transient] || (cfg.scalaTransientSupport && aTpe =:= TypeRepr .of[scala.transient])) {
1189
+ if (isTransient) warn(s " Duplicated $supportedTransientTypeNames defined for ' $name' of ' ${tpe.show}'. " )
1190
+ isTransient = true
1191
+ }
1192
+ }
1193
+ if (((named ne None ) || isStringified) && isTransient) {
1194
+ warn(s " Both $supportedTransientTypeNames and ' ${Type .show[named]}' or " +
1195
+ s " $supportedTransientTypeNames and ' ${Type .show[stringified]}' defined for ' $name' of ' ${tpe.show}'. " )
1196
+ }
1197
+ val mappedName = namedValueOpt(named, tpe) match
1198
+ case Some (name1) => name1
1199
+ case _ => cfg.fieldNameMapper(name) match
1200
+ case Some (name2) => name2
1201
+ case _ => name
1206
1202
val index = fieldIndex(isTransient)
1207
1203
new FieldInfo (symbol, mappedName, getterOrField, defaultValue, fieldTpe, isTransient, isStringified, index)
1208
1204
}
0 commit comments