@@ -809,8 +809,6 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
809809 }
810810 }
811811
812- private case class FieldAnnotations (partiallyMappedName : Option [String ], transient : Boolean , stringified : Boolean )
813-
814812 private case class DecoderMethodKey (tpe : TypeRepr , isStringified : Boolean , useDiscriminator : Boolean )
815813
816814 private case class EncoderMethodKey (tpe : TypeRepr , isStringified : Boolean , discriminatorKeyValue : Option [(String , String )])
@@ -846,15 +844,19 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
846844 private val unitTpe = defn.UnitClass .typeRef
847845 private val anyTpe = defn.AnyClass .typeRef
848846 private val arrayOfAnyTpe = defn.ArrayClass .typeRef.appliedTo(anyTpe)
849- private val iArrayOfAnyRefTpe = TypeRepr .of[IArray [AnyRef ]]
850847 private val stringTpe = TypeRepr .of[String ]
848+ private val optionTpe = TypeRepr .of[Option [? ]]
851849 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 ]]
852854 private val jsonKeyCodecTpe = TypeRepr .of[JsonKeyCodec ]
853855 private val jsonValueCodecTpe = TypeRepr .of[JsonValueCodec ]
854856 private val newArray = Select (New (TypeIdent (defn.ArrayClass )), defn.ArrayClass .primaryConstructor)
855857 private val newArrayOfAny = TypeApply (newArray, List (Inferred (anyTpe)))
856858 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
858860 private val inferredKeyCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonKeyCodec [? ]]]]
859861 private val inferredValueCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonValueCodec [? ]]]]
860862 private val inferredOrderings = new mutable.HashMap [TypeRepr , Term ]
@@ -959,17 +961,17 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
959961 else tpe.typeSymbol.companionModule
960962 }
961963
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 ))
964966
965967 private def isNullable (tpe : TypeRepr ): Boolean = tpe match
966968 case OrType (left, right) => isNullable(right) || isNullable(left)
967969 case _ => tpe =:= TypeRepr .of[Null ]
968970
969971 private def isIArray (tpe : TypeRepr ): Boolean = tpe.typeSymbol.fullName == " scala.IArray$package$.IArray"
970972
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)
973975
974976 private def isJavaEnum (tpe : TypeRepr ): Boolean = tpe <:< TypeRepr .of[java.lang.Enum [? ]]
975977
@@ -1121,43 +1123,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11211123 })
11221124
11231125 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-
11301126 def supportedTransientTypeNames : String =
11311127 if (cfg.scalaTransientSupport) s " ' ${Type .show[transient]}' (or ' ${Type .show[scala.transient]}') "
11321128 else s " ' ${Type .show[transient]}') "
11331129
11341130 val tpeTypeArgs = typeArgs(tpe)
11351131 val tpeClassSym = tpe.classSymbol.getOrElse(fail(s " Expected that ${tpe.show} has classSymbol " ))
11361132 val primaryConstructor = tpeClassSym.primaryConstructor
1137- var annotations = Map .empty[String , FieldAnnotations ]
11381133 val caseFields = tpeClassSym.caseFields
1139- var companionRefAndMembers : (Ref , List [Symbol ]) = null
11401134 var fieldMembers : List [Symbol ] = null
1135+ var companionRefAndClass : (Ref , Symbol ) = null
11411136 var methodMembers : List [Symbol ] = null
11421137
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-
11611138 def createFieldInfos (params : List [Symbol ], typeParams : List [Symbol ], fieldIndex : Boolean => Int ): List [FieldInfo ] = params.map {
11621139 var i = 0
11631140 symbol =>
@@ -1171,20 +1148,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11711148 case _ : TypeBounds =>
11721149 fail(s " Type bounds are not supported for type ' ${tpe.show}' with field type for $name ' ${fieldTpe.show}' " )
11731150 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 ) {
11771153 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)
11861155 }
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
11881163 val getterOrField = caseFields.find(_.name == name) match
11891164 case Some (caseField) => caseField
11901165 case _ =>
@@ -1199,10 +1174,31 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11991174 if (! getterOrField.exists || getterOrField.flags.is(Flags .PrivateLocal )) {
12001175 fail(s " Getter or field ' $name' of ' ${tpe.show}' is private. It should be defined as 'val' or 'var' in the primary constructor. " )
12011176 }
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
12061202 val index = fieldIndex(isTransient)
12071203 new FieldInfo (symbol, mappedName, getterOrField, defaultValue, fieldTpe, isTransient, isStringified, index)
12081204 }
0 commit comments