Skip to content

Commit 5a728b1

Browse files
authored
Add scala 3 impl and tests for openapi method variants (#1282)
1 parent 74850ac commit 5a728b1

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,52 @@ object JsonCodecMaker {
587587
*/
588588
inline def makeCirceLikeSnakeCased[A]: JsonValueCodec[A] = ${Impl.makeCirceLikeSnakeCased}
589589

590+
/**
591+
* Replacements for the `make` call preconfigured to behave as expected by openapi specifications:
592+
* `CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false).withRequireCollectionFields(true).withAllowRecursiveTypes(true)`
593+
*
594+
* @tparam A a type that should be encoded and decoded by the derived codec
595+
* @return an instance of the derived codec
596+
*/
597+
inline def makeOpenapiLike[A]: JsonValueCodec[A] = ${Impl.makeOpenapiLike}
598+
599+
/**
600+
* Replacements for the `make` call preconfigured to behave as expected by openapi specifications:
601+
* `CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false).withRequireCollectionFields(true).withAllowRecursiveTypes(true)`
602+
* with a privided discriminator field name.
603+
*
604+
* @tparam A a type that should be encoded and decoded by the derived codec
605+
* @param discriminatorFieldName a name of discriminator field
606+
* @return an instance of the derived codec
607+
*/
608+
inline def makeOpenapiLike[A](discriminatorFieldName: String): JsonValueCodec[A] =
609+
${Impl.makeOpenapiLike('discriminatorFieldName)}
610+
611+
/**
612+
* Replacements for the `make` call preconfigured to behave as expected by openapi specifications:
613+
* `CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false).withRequireCollectionFields(true).withAllowRecursiveTypes(true)`
614+
* with a privided discriminator field name and an ADT leaf-class name mapper with sequentionally applied function
615+
* that truncates to simple class name by default
616+
*
617+
* @tparam A a type that should be encoded and decoded by the derived codec
618+
* @param discriminatorFieldName a name of discriminator field
619+
* @param adtLeafClassNameMapper the function of mapping from string of case class/object full name to string value of
620+
* discriminator field
621+
* @return an instance of the derived codec
622+
*/
623+
inline def makeOpenapiLike[A](discriminatorFieldName: String, inline adtLeafClassNameMapper: PartialFunction[String, String]): JsonValueCodec[A] =
624+
${Impl.makeOpenapiLike('discriminatorFieldName, 'adtLeafClassNameMapper)}
625+
626+
/**
627+
* Replacements for the `make` call preconfigured to behave as expected by openapi specifications:
628+
* `CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false).withRequireCollectionFields(true).withAllowRecursiveTypes(true).withDiscriminatorFieldName(scala.None))`
629+
*
630+
* @tparam A a type that should be encoded and decoded by the derived codec
631+
* @return an instance of the derived codec
632+
*/
633+
inline def makeOpenapiLikeWithoutDiscriminator[A]: JsonValueCodec[A] =
634+
${Impl.makeOpenapiLikeWithoutDiscriminator}
635+
590636
/**
591637
* Derives a codec for JSON values for the specified type `A` and a provided derivation configuration.
592638
*
@@ -652,6 +698,30 @@ object JsonCodecMaker {
652698
inlineOneValueClasses = false,
653699
alwaysEmitDiscriminator = false))
654700

701+
def makeOpenapiLike[A: Type](using Quotes): Expr[JsonValueCodec[A]] =
702+
make(CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false)
703+
.withRequireCollectionFields(true).withAllowRecursiveTypes(true))
704+
705+
def makeOpenapiLike[A: Type](discriminatorFieldName: Expr[String])(using Quotes): Expr[JsonValueCodec[A]] =
706+
make(CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false)
707+
.withRequireCollectionFields(true).withAllowRecursiveTypes(true)
708+
.withDiscriminatorFieldName(Some(discriminatorFieldName.valueOrAbort)))
709+
710+
def makeOpenapiLike[A: Type](discriminatorFieldName: Expr[String],
711+
adtLeafClassNameMapper: Expr[PartialFunction[String, String]])(using Quotes): Expr[JsonValueCodec[A]] =
712+
make(
713+
CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false)
714+
.withRequireCollectionFields(true).withAllowRecursiveTypes(true)
715+
.withDiscriminatorFieldName(Some(discriminatorFieldName.valueOrAbort))
716+
.withAdtLeafClassNameMapper(ExprPartialFunctionWrapper(adtLeafClassNameMapper).apply.unlift
717+
.compose(PartialFunction.fromFunction(simpleClassName))))
718+
719+
def makeOpenapiLikeWithoutDiscriminator[A: Type](using Quotes): Expr[JsonValueCodec[A]] =
720+
make(CodecMakerConfig.withTransientEmpty(false).withTransientDefault(false)
721+
.withRequireCollectionFields(true).withAllowRecursiveTypes(true)
722+
.withDiscriminatorFieldName(None))
723+
724+
655725
def makeWithSpecifiedConfig[A: Type](config: Expr[CodecMakerConfig])(using Quotes): Expr[JsonValueCodec[A]] = {
656726
import quotes.reflect._
657727

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,22 @@ class JsonCodecMakerSpec extends VerifyingSpec {
24292429
verifyDeser(baseCodec2, B(), """{"B":{"extra":"should be ignored"}}""")
24302430
verifyDeser(baseCodec2, C, """"C"""")
24312431
}
2432+
"serialize and deserialize ADTs with openapi-like formatting" in {
2433+
sealed trait Enum
2434+
2435+
object EnumValue1 extends Enum
2436+
2437+
object EnumValue2 extends Enum
2438+
2439+
verifySerDeser(makeOpenapiLike[Enum], EnumValue1, """{"type":"EnumValue1"}""")
2440+
verifySerDeser(makeOpenapiLike[Enum]("hint"), EnumValue2, """{"hint":"EnumValue2"}""")
2441+
val codec: JsonValueCodec[Enum] = makeOpenapiLike("hint", {
2442+
case "EnumValue1" => "enum_value_1"
2443+
case "EnumValue2" => "enum_value_2"
2444+
})
2445+
verifySerDeser(codec, EnumValue1, """{"hint":"enum_value_1"}""")
2446+
verifySerDeser(makeOpenapiLikeWithoutDiscriminator[Enum], EnumValue2, """"EnumValue2"""")
2447+
}
24322448
"serialize and deserialize ADTs with circe-like default formatting" in {
24332449
sealed trait Enum
24342450

0 commit comments

Comments
 (0)