@@ -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,22 @@ 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 ]]
854+ private val namedTpe = TypeRepr .of[named]
855+ private val stringifiedTpe = TypeRepr .of[stringified]
856+ private val transientTpe = TypeRepr .of[transient]
852857 private val jsonKeyCodecTpe = TypeRepr .of[JsonKeyCodec ]
853858 private val jsonValueCodecTpe = TypeRepr .of[JsonValueCodec ]
854859 private val newArray = Select (New (TypeIdent (defn.ArrayClass )), defn.ArrayClass .primaryConstructor)
855860 private val newArrayOfAny = TypeApply (newArray, List (Inferred (anyTpe)))
856861 private val fromIArrayMethod = Select .unique(Ref (Symbol .requiredModule(" scala.runtime.TupleXXL" )), " fromIArray" )
857- private val asInstanceOfMethod = anyTpe.typeSymbol.methodMember (" asInstanceOf" ).head
862+ private val asInstanceOfMethod = anyTpe.typeSymbol.declaredMethod (" asInstanceOf" ).head
858863 private val inferredKeyCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonKeyCodec [? ]]]]
859864 private val inferredValueCodecs = new mutable.HashMap [TypeRepr , Option [Expr [JsonValueCodec [? ]]]]
860865 private val inferredOrderings = new mutable.HashMap [TypeRepr , Term ]
@@ -959,17 +964,17 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
959964 else tpe.typeSymbol.companionModule
960965 }
961966
962- private def isOption (tpe : TypeRepr , types : List [TypeRepr ]): Boolean = tpe <:< TypeRepr .of[ Option [ ? ]] &&
963- (cfg.skipNestedOptionValues || ! types.headOption.exists(_ <:< TypeRepr .of[ Option [ ? ]] ))
967+ private def isOption (tpe : TypeRepr , types : List [TypeRepr ]): Boolean = tpe <:< optionTpe &&
968+ (cfg.skipNestedOptionValues || ! types.headOption.exists(_ <:< optionTpe ))
964969
965970 private def isNullable (tpe : TypeRepr ): Boolean = tpe match
966971 case OrType (left, right) => isNullable(right) || isNullable(left)
967972 case _ => tpe =:= TypeRepr .of[Null ]
968973
969974 private def isIArray (tpe : TypeRepr ): Boolean = tpe.typeSymbol.fullName == " scala.IArray$package$.IArray"
970975
971- private def isCollection (tpe : TypeRepr ): Boolean = tpe <:< TypeRepr .of[ Iterable [ ? ]] ||
972- tpe <:< TypeRepr .of[ Iterator [ ? ]] || tpe <:< TypeRepr .of[ Array [ ? ]] || isIArray(tpe)
976+ private def isCollection (tpe : TypeRepr ): Boolean =
977+ tpe <:< iterableTpe || tpe <:< iteratorTpe || tpe <:< arrayTpe || isIArray(tpe)
973978
974979 private def isJavaEnum (tpe : TypeRepr ): Boolean = tpe <:< TypeRepr .of[java.lang.Enum [? ]]
975980
@@ -1121,43 +1126,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11211126 })
11221127
11231128 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-
11301129 def supportedTransientTypeNames : String =
1131- if (cfg.scalaTransientSupport) s " ' ${Type .show[transient] }' (or ' ${Type .show [scala.transient]}') "
1132- else s " ' ${Type .show[transient] }') "
1130+ if (cfg.scalaTransientSupport) s " ' ${transientTpe .show}' (or ' ${TypeRepr .of [scala.transient].show }') "
1131+ else s " ' ${transientTpe .show}') "
11331132
11341133 val tpeTypeArgs = typeArgs(tpe)
11351134 val tpeClassSym = tpe.classSymbol.getOrElse(fail(s " Expected that ${tpe.show} has classSymbol " ))
11361135 val primaryConstructor = tpeClassSym.primaryConstructor
1137- var annotations = Map .empty[String , FieldAnnotations ]
11381136 val caseFields = tpeClassSym.caseFields
1139- var companionRefAndMembers : (Ref , List [Symbol ]) = null
11401137 var fieldMembers : List [Symbol ] = null
1138+ var companionRefAndClass : (Ref , Symbol ) = null
11411139 var methodMembers : List [Symbol ] = null
11421140
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-
11611141 def createFieldInfos (params : List [Symbol ], typeParams : List [Symbol ], fieldIndex : Boolean => Int ): List [FieldInfo ] = params.map {
11621142 var i = 0
11631143 symbol =>
@@ -1171,20 +1151,18 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11711151 case _ : TypeBounds =>
11721152 fail(s " Type bounds are not supported for type ' ${tpe.show}' with field type for $name ' ${fieldTpe.show}' " )
11731153 case _ =>
1174- val defaultValue = if (! cfg.requireDefaultFields && symbol.flags.is(Flags .HasDefault )) {
1175- val dvMemberName = " $lessinit$greater$default$" + i
1176- if (companionRefAndMembers eq null ) {
1154+ val defaultValue = if (! cfg.requireDefaultFields && symbol.flags.is(Flags .HasDefault )) new Some ({
1155+ if (companionRefAndClass eq null ) {
11771156 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" )
1157+ companionRefAndClass = (Ref (typeSymbol.companionModule), typeSymbol.companionClass)
11861158 }
1187- } else None
1159+ val methodSymbol = companionRefAndClass._2.declaredMethod(" $lessinit$greater$default$" + i).head
1160+ val dvSelectNoTypes = Select (companionRefAndClass._1, methodSymbol)
1161+ methodSymbol.paramSymss match
1162+ case Nil => dvSelectNoTypes
1163+ case List (params) if params.exists(_.isTypeParam) => TypeApply (dvSelectNoTypes, tpeTypeArgs.map(Inferred (_)))
1164+ case paramss => fail(s " Default method for $name of class ${tpe.show} have a complex parameter list: $paramss" )
1165+ }) else None
11881166 val getterOrField = caseFields.find(_.name == name) match
11891167 case Some (caseField) => caseField
11901168 case _ =>
@@ -1199,10 +1177,31 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
11991177 if (! getterOrField.exists || getterOrField.flags.is(Flags .PrivateLocal )) {
12001178 fail(s " Getter or field ' $name' of ' ${tpe.show}' is private. It should be defined as 'val' or 'var' in the primary constructor. " )
12011179 }
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)
1180+ var named : Option [Term ] = None
1181+ var isStringified : Boolean = false
1182+ var isTransient : Boolean = false
1183+ getterOrField.annotations.foreach { annotation =>
1184+ val aTpe = annotation.tpe
1185+ if (aTpe =:= namedTpe) {
1186+ if (named eq None ) named = new Some (annotation)
1187+ else fail(s " Duplicated ' ${namedTpe.show}' defined for ' $name' of ' ${tpe.show}'. " )
1188+ } else if (aTpe =:= stringifiedTpe) {
1189+ if (isStringified) warn(s " Duplicated ' ${stringifiedTpe.show}' defined for ' $name' of ' ${tpe.show}'. " )
1190+ isStringified = true
1191+ } else if (aTpe =:= transientTpe || (cfg.scalaTransientSupport && aTpe =:= TypeRepr .of[scala.transient])) {
1192+ if (isTransient) warn(s " Duplicated $supportedTransientTypeNames defined for ' $name' of ' ${tpe.show}'. " )
1193+ isTransient = true
1194+ }
1195+ }
1196+ if (((named ne None ) || isStringified) && isTransient) {
1197+ warn(s " Both $supportedTransientTypeNames and ' ${namedTpe.show}' or " +
1198+ s " $supportedTransientTypeNames and ' ${stringifiedTpe.show}' defined for ' $name' of ' ${tpe.show}'. " )
1199+ }
1200+ val mappedName = namedValueOpt(named, tpe) match
1201+ case Some (name1) => name1
1202+ case _ => cfg.fieldNameMapper(name) match
1203+ case Some (name2) => name2
1204+ case _ => name
12061205 val index = fieldIndex(isTransient)
12071206 new FieldInfo (symbol, mappedName, getterOrField, defaultValue, fieldTpe, isTransient, isStringified, index)
12081207 }
0 commit comments