Skip to content

Commit 8803795

Browse files
committed
Fix unexpected instantiation of a new value of case object class when using Scala 3 derives for codec derivation
1 parent b57c381 commit 8803795

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

jsoniter-scala-macros/shared/src/main/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ object JsonCodecMaker {
781781
case ConstantType(_) => true
782782
case _ => false
783783

784-
def isEnumOrModuleValue(tpe: TypeRepr): Boolean = tpe.isSingleton &&
784+
def isEnumOrModuleValue(tpe: TypeRepr): Boolean =
785785
(tpe.typeSymbol.flags.is(Flags.Module) || tpe.termSymbol.flags.is(Flags.Enum))
786786

787787
def isOption(tpe: TypeRepr, types: List[TypeRepr]): Boolean = tpe <:< TypeRepr.of[Option[_]] &&
@@ -1787,8 +1787,9 @@ object JsonCodecMaker {
17871787
tpe match
17881788
case ConstantType(c) => Literal(c).asExprOf[T]
17891789
case _ => cannotFindValueCodecError(tpe)
1790-
} else if (isEnumOrModuleValue(tpe)) Ref(tpe.termSymbol).asExprOf[T] // FIXME: add support of non top-level defiend enums
1791-
else if (isValueClass(tpe)) {
1790+
} else if (isEnumOrModuleValue(tpe)) {
1791+
Ref(if (tpe.termSymbol.flags.is(Flags.Enum)) tpe.termSymbol else tpe.typeSymbol.companionModule).asExprOf[T]
1792+
} else if (isValueClass(tpe)) {
17921793
val tpe1 = valueClassValueType(tpe)
17931794
tpe1.asType match
17941795
case '[t1] => getClassInfo(tpe).genNew(genNullValue[t1](tpe1 :: types).asTerm).asExprOf[T]
@@ -1828,8 +1829,9 @@ object JsonCodecMaker {
18281829
if (currentDiscriminator.isDefined) '{
18291830
$in.rollbackToMark()
18301831
${genReadLeafClass[st](subTpe)}
1831-
} else if (!cfg.circeLikeObjectEncoding && isEnumOrModuleValue(subTpe)) Ref(subTpe.termSymbol).asExprOf[st]
1832-
else if (!cfg.circeLikeObjectEncoding && subTpe =:= TypeRepr.of[None.type]) '{ None }.asExprOf[st]
1832+
} else if (!cfg.circeLikeObjectEncoding && isEnumOrModuleValue(subTpe)) {
1833+
Ref(if (subTpe.termSymbol.flags.is(Flags.Enum)) subTpe.termSymbol else subTpe.typeSymbol.companionModule).asExprOf[T]
1834+
} else if (!cfg.circeLikeObjectEncoding && subTpe =:= TypeRepr.of[None.type]) '{ None }.asExprOf[st]
18331835
else genReadLeafClass[st](subTpe)
18341836
} else $acc
18351837
}.asExprOf[T]
@@ -2629,11 +2631,12 @@ object JsonCodecMaker {
26292631
else $in.readNullOrTokenError($default, '[')
26302632
}
26312633
} else if (isEnumOrModuleValue(tpe) || tpe =:= TypeRepr.of[None.type]) withDecoderFor(methodKey, default, in) { (in, default) =>
2634+
val x = Ref(if (tpe.termSymbol.flags.is(Flags.Enum)) tpe.termSymbol else tpe.typeSymbol.companionModule).asExprOf[T]
26322635
'{
26332636
if ($in.isNextToken('{')) {
26342637
$in.rollbackToken()
26352638
$in.skip()
2636-
${if (tpe =:= TypeRepr.of[None.type]) '{ None }.asExprOf[T] else Ref(tpe.termSymbol).asExprOf[T]} // FIXME: add support of non top-level defiend enums
2639+
$x
26372640
} else $in.readNullOrTokenError($default, '{')
26382641
}
26392642
} else if (isSealedClass(tpe)) withDecoderFor(methodKey, default, in) { (in, default) =>

jsoniter-scala-macros/shared/src/test/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMakerNewKeywordSpec.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ class JsonCodecMakerNewKeywordSpec extends VerifyingSpec {
113113

114114
verifySerDeser(summon[JsonValueCodec[TestEnum]], TestEnum.Value2("VVV"), """{"hint":"Value2","str":"VVV"}""")
115115
}
116+
{
117+
inline given CodecMakerConfig = CodecMakerConfig.withDiscriminatorFieldName(None)
118+
119+
sealed trait TestEnum derives ConfiguredJsonValueCodec
120+
121+
case object Value1 extends TestEnum derives ConfiguredJsonValueCodec
122+
123+
case class Value2(string: String) extends TestEnum derives ConfiguredJsonValueCodec
124+
125+
verifyDeserByCheck(summon[JsonValueCodec[Value1.type]], """{}""", x => assert(x eq Value1)) // yes! in macros you can instantiate a new value of case object class
126+
verifySerDeser(make[List[TestEnum]], List(Value1, Value2("VVV")), """["Value1",{"Value2":{"string":"VVV"}}]""")
127+
}
116128
}
117129
"serialize and deserialize an generic ADT defined with bounded leaf classes using a custom codec" in {
118130
sealed trait TypeBase[T]

0 commit comments

Comments
 (0)