From 89edef530a3c9212ea595d1be07e3319f09d6685 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Wed, 29 Jan 2025 15:17:57 +0100 Subject: [PATCH] More efficient encoding of case classes --- .../src/main/scala-2.x/zio/json/macros.scala | 14 ++++++++++---- .../shared/src/main/scala-3/zio/json/macros.scala | 6 +++++- .../scala/zio/json/internal/FieldEncoder.scala | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/zio-json/shared/src/main/scala-2.x/zio/json/macros.scala b/zio-json/shared/src/main/scala-2.x/zio/json/macros.scala index 369bb1e8..23eb12f6 100644 --- a/zio-json/shared/src/main/scala-2.x/zio/json/macros.scala +++ b/zio-json/shared/src/main/scala-2.x/zio/json/macros.scala @@ -546,9 +546,15 @@ object DeriveJsonEncoder { var idx = 0 var prevFields = false // whether any fields have been written while (idx < fields.length) { - val field = fields(idx) - val p = field.p.dereference(a) - field.encodeOrSkip(p) { () => + val field = fields(idx) + val p = field.p.dereference(a) + val encoder = field.encoder + if ( + (field.withExplicitNulls && field.withExplicitEmptyCollections) || + (field.withExplicitNulls && !encoder.isEmpty(p)) || + (field.withExplicitEmptyCollections && !encoder.isNothing(p)) || + (!encoder.isEmpty(p) && !encoder.isNothing(p)) + ) { // if we have at least one field already, we need a comma if (prevFields) { out.write(',') @@ -557,7 +563,7 @@ object DeriveJsonEncoder { JsonEncoder.string.unsafeEncode(field.name, indent_, out) if (indent.isEmpty) out.write(':') else out.write(" : ") - field.encoder.unsafeEncode(p, indent_, out) + encoder.unsafeEncode(p, indent_, out) prevFields = true // record that we have at least one field so far } idx += 1 diff --git a/zio-json/shared/src/main/scala-3/zio/json/macros.scala b/zio-json/shared/src/main/scala-3/zio/json/macros.scala index 99f857f7..72c31b07 100644 --- a/zio-json/shared/src/main/scala-3/zio/json/macros.scala +++ b/zio-json/shared/src/main/scala-3/zio/json/macros.scala @@ -601,7 +601,11 @@ sealed class JsonEncoderDerivation(config: JsonCodecConfiguration) extends Deriv while (idx < fields.length) { val field = fields(idx) val p = field.p.deref(a) - field.encodeOrSkip(p) { () => + val encoder = field.encoder + if ((field.withExplicitNulls && field.withExplicitEmptyCollections) || + (field.withExplicitNulls && !encoder.isEmpty(p)) || + (field.withExplicitEmptyCollections && !encoder.isNothing(p)) || + (!encoder.isEmpty(p) && !encoder.isNothing(p))) { // if we have at least one field already, we need a comma if (prevFields) { out.write(',') diff --git a/zio-json/shared/src/main/scala/zio/json/internal/FieldEncoder.scala b/zio-json/shared/src/main/scala/zio/json/internal/FieldEncoder.scala index ac2cbc34..79183756 100644 --- a/zio-json/shared/src/main/scala/zio/json/internal/FieldEncoder.scala +++ b/zio-json/shared/src/main/scala/zio/json/internal/FieldEncoder.scala @@ -8,8 +8,8 @@ private[json] class FieldEncoder[T, P]( val p: P, val name: String, val encoder: JsonEncoder[T], - withExplicitNulls: Boolean, - withExplicitEmptyCollections: Boolean + val withExplicitNulls: Boolean, + val withExplicitEmptyCollections: Boolean ) { private[this] val _encodeOrSkip: T => (() => Unit) => Unit = if (withExplicitNulls && withExplicitEmptyCollections) { _ => encode =>