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

Add support for generic tristate (undefined | null | defined) codec #107

Open
myuwono opened this issue Nov 26, 2022 · 2 comments · May be fixed by #108
Open

Add support for generic tristate (undefined | null | defined) codec #107

myuwono opened this issue Nov 26, 2022 · 2 comments · May be fixed by #108
Assignees
Labels
enhancement New feature or request

Comments

@myuwono
Copy link
Collaborator

myuwono commented Nov 26, 2022

Feature Request

  • add support for serialization / deseiralization of TriState<A> which models Absent | Null | Defined<A>

Context

There are times where users need to model an API that need differentiate between:

  • absence of a field
  • presence of a field in json, but being set to null
  • presence of a field in json, with a value set

An example is a PATCH endpoint that may have the following contract:

// modify nickname
PATCH /api/user/{id} { "nickname" : "john doe" }

// deletes nickname
PATCH /api/user/{id} { "nickname" : null }

// does nothing
PATCH /api/user/{id} { }

Currently nullables T? is not a viable alternative as they are missing a degree of freedom (the absence) and hence isn't usable. As well, Option<T> is generally used to treat missing and absence as None by convention. While Option<T?> is likely to be a possible container type for this, it is somewhat not feasible to be used due to null being a synthetic type. I.e. somehow Jackson could not differentiate whether the type signature requested is nullable or not at runtime, or at least I could not find a way to do so with my limited knowledge.

A possible alternative would be to define a TriState<A> as follows:

sealed class TriState<out A> {
  companion object

  object Absent : TriState<Nothing>()
  object Null : TriState<Nothing>()
  data class Defined<T>(val value: T) : TriState<T>()
}

Given the code above we'd have a concrete distinction between Absent or Null that Jackson can use. This makes modelling the above behaviour possible. Additionally, this model can be bi-directionally converted to Arrow's Option<T?> or Option<Option<T>> without loss of precision which hopefully should support the ergonomic and integration with the rest of the arrow ecosystem.

Another alternative would be to expose a module that users can use to implement such sealed class within their own codebase e.g. GenericTriStateModule<T>.

@myuwono myuwono added the enhancement New feature or request label Nov 26, 2022
@myuwono myuwono self-assigned this Nov 27, 2022
@myuwono myuwono changed the title Add special data type to support generic tristate serialization / deserialization Add support for generic tristate (undefined | null | defined) serialization / deserialization Nov 27, 2022
@myuwono myuwono changed the title Add support for generic tristate (undefined | null | defined) serialization / deserialization Add support for generic tristate (undefined | null | defined) codec Nov 27, 2022
@myuwono myuwono linked a pull request Nov 27, 2022 that will close this issue
@christophejan
Copy link

Hello @myuwono, I just quickly read this issue and that make me think of jackson-databind-nullable. I don’t know if you already check this module but perhaps it can help.

@myuwono
Copy link
Collaborator Author

myuwono commented Dec 14, 2022

Thank you @christophejan I wasn't aware of that project. That one is interesting. JsonNullable<T> does have the similar objective, approached using using the Java Optional-ish approach instead of Kotlin sealed class. I was initially on the fence whether or not a new type would be necessary. After looking into that library, it appears that a new dedicated type would indeed be a good addition to arrow-integrations-jackson. We will need a good name for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants