Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If a data class has a List parameter, default value emptyList(), encode to string does not return empty json array #1447

Closed
aSemy opened this issue May 1, 2021 · 5 comments

Comments

@aSemy
Copy link
Contributor

aSemy commented May 1, 2021

Describe the bug

Given a data class with a parameter List<String>? which has a default value of emptyList(), when an instance of that class is encoded to string, then the field is not included in the resulting json - the field is missing. An empty json array [] was expected.

Expected: {"name":"Fido", "tags":[]}
Actual: {"name":"Fido"}

Note that if the List<String>? parameter has a default of null, and when it is created it is set to emptyList(), then encodeToString(...) works correctly, and an empty json array is produced.

To Reproduce

import io.kotest.core.spec.style.AnnotationSpec
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.javacrumbs.jsonunit.assertj.assertThatJson

@Serializable
data class Dog(
  @SerialName("name")
  val name: String? = null,
  @SerialName("tags")
  val tags: List<String>? = emptyList(),
  @SerialName("size")
  val size: Int? = null,
)

@Serializable
data class Cat(
  @SerialName("name")
  val name: String? = null,
  @SerialName("tags")
  val tags: List<String>? = null,
  @SerialName("size")
  val size: Int? = null,
)

class EmptyList : AnnotationSpec() {

  private val jsonFormatter = Json {
    prettyPrint = true
  }

  @Test
  fun `test encode Dog to string`() {

    val pet = Dog(
      name = "Fido",
      tags = emptyList(),
    )

    val petJson = jsonFormatter.encodeToString(pet)

    assertThatJson(petJson)
      .isEqualTo("""
        {
          "name": "Fido",
          "tags": []
        }
      """.trimIndent())
    // Different keys found in node "", missing: "tags",
    // expected: <{"name":"Fido","tags":[]}>
    // but was: <{"name":"Fido"}>
  }

  @Test
  fun `test encode Cat to string`() {

    val pet = Cat(
      name = "Poesje",
      tags = emptyList(),
    )

    val petJson = jsonFormatter.encodeToString(pet)

    assertThatJson(petJson)
      .isEqualTo("""
        {
          "name": "Poesje",
          "tags": []
        }
      """.trimIndent())
    // passes
  }
}

Environment

  • Kotlin jvm: 1.4.32
  • kotlinx-serialization-json: 1.1.0
  • json-unit-assertj: 2.25.0
  • kotest: 4.5.0.RC1
  • jvm 11
  • gradle 7.0
@mirjalal
Copy link

mirjalal commented May 2, 2021

Set encodeDefaults as true for the jsonFormatter as documented here:

private val jsonFormatter = Json {
    encodeDefaults = true,
    prettyPrint = true
}

HTH! Cheers.

p.s. I have tested it & it worked as expected (on my machine).

@aSemy
Copy link
Contributor Author

aSemy commented May 2, 2021

Thanks, but that results in the val size: Int? = null being encoded to string as null, which isn't what I want.

In the example test I posted, if I add encodeDefaults

  private val jsonFormatter = Json {
    prettyPrint = true
    encodeDefaults = true
  }

Then both tests fail

Cat:

Different keys found in node "", extra: "size", 
expected: <{"name":"Poesje","tags":[]}> 
but was: <{"name":"Poesje","size":null,"tags":[]}>

Dog:

Different keys found in node "", extra: "size", 
expected: <{"name":"Fido","tags":[]}> 
but was: <{"name":"Fido","size":null,"tags":[]}>

I am expecting that

val pet = Dog(
  name = "Fido",
  tags = emptyList(),
)

should have a json path tags=[], no matter what the default parameter of tags in the data class is.

Instead, I only get tags=[] when either

  1. the tags default parameter is null and I specify emptyList() in the constructor.
  2. I enable encodeDefaults and set a default emptyList() on the data class parameter

@Dominaezzz
Copy link
Contributor

This might be of interest then. #195

@ArcticLampyrid
Copy link

Providing EncodeDefault annotation per field can be helpful to this situation.
#1091

@aSemy
Copy link
Contributor Author

aSemy commented Jan 12, 2022

I think this has been resolved by #1091 - thanks!

@aSemy aSemy closed this as completed Jan 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants