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

Global custom serializers #507

Open
sksamuel opened this issue Jul 4, 2019 · 23 comments
Open

Global custom serializers #507

sksamuel opened this issue Jul 4, 2019 · 23 comments
Labels
feature Static modules Request for serializer that can be added to Java module

Comments

@sksamuel
Copy link
Contributor

sksamuel commented Jul 4, 2019

What is your use-case and why do you need this feature?

If you have a data class with many "unsupported" types, but very common types in the JDK it is unweidly to use @ContextualSerialization everywhere - either on a file basic or a property basis.

For example,

data class Foo(val decimal: BigDecimal, val id: UUID, val date: LocalDateTime)

Three types, needing three @ContextualSerialization.

Describe the solution you'd like

Some way of registering global serializers.

@sandwwraith
Copy link
Member

We have several concerns regarding this:

  1. Implicitness – it is very easy to forget and hard to find which serializer is used for UUID in a particular class. Easy to mess/mix things up.
  2. Security – you may accidentally deserialize data that you didn't want to in some area of the program
  3. Modules, incremental compilation – since serializers are compiled into the code by the plugin, changing global settings would require to recompile the whole module.

However, these problems may not concern small or mid-size applications. Probably this restriction would be relaxed in the future.

@sksamuel
Copy link
Contributor Author

sksamuel commented Jul 11, 2019

Valid concerns, but here are a couple of points from the other side.

  1. Common types like BigDecimal, UUID, javax dates, etc are not supported at the moment. It's tedious and error prone to annotate every instance of these. These are extremely common base JDK types - in my code base for example a domain type could have 10 of these out of 30 fields, across hundreds of domain objects. Financial domain objects will use BigDecimals everywhere.

  2. The most popular serialisation frameworks - think Jackson for example - handle serialization of any types. Jackson will serialize everything. So there must be a way to make this work.

Edited: Removed GSON from 2.

@JakeWharton
Copy link
Contributor

The Gson maintainers think point 2 is a failure of the library and have not supported this feature in Moshi (aka Gson v3). It has absolutely caused problems in practice.

@sksamuel
Copy link
Contributor Author

Ok I stand corrected on Gson. It's still a feature / bug (delete as appropriate) of Jackson though.

@pdvrieze
Copy link
Contributor

I'm not sure whether it is actually valid (or easy to do), but package level annotations would be the way to go. I know it is possible in Java using package-info.java, but I've got no idea whether Kotlin could use such annotations in the compiler.

@sandwwraith
Copy link
Member

AFAIR, Kotlin doesn't support package-level annotation. It recognizes annotations on package-info.java, but this requires enabling Java support in JVM target (hence, no MPP).

@pdvrieze
Copy link
Contributor

@sandwwraith Was afraid that was the case. The only other option I can come up with would be some way to add annotations to an annotationB and have this annotation B be used as a shorthand wherever needed.

@marco-eckstein
Copy link

Not global, but the file-level annotation @file:UseSerializers(MySerializer::class) mitigates the problem. See Specifying serializers for a file.

@nuhkoca
Copy link

nuhkoca commented May 7, 2021

Any update on this?

@sandwwraith
Copy link
Member

@nuhkoca Not for now, this problem was postponed

@sandwwraith sandwwraith added the Static modules Request for serializer that can be added to Java module label Oct 6, 2021
@angryziber
Copy link

Wouldn't it be easy and logical to provide additional serializers to JsonBuilder?
Currently only contextual and polyomorphic serializers can be provided...

@sandwwraith
Copy link
Member

@angryziber This would provide serializers for Json format, but not for e.g. Protobuf. I assume this issue is about specifying a serializer for a type for a whole module for all formats

@pdvrieze
Copy link
Contributor

Wouldn't it be easy and logical to provide additional serializers to JsonBuilder?
Currently only contextual and polyomorphic serializers can be provided...

The "best" way would be to expose serializers in module metadata and then resolve them from this metadata. The question there is mainly how conflict resolution happens (which serializer should be used if there are multiple, and how can a developer override that - in some way the place would be some kind of module-info.kt)

@angryziber
Copy link

@sandwwraith as I understand, serializers are format-neutral, i.e. they describe the structure of the object and serialization can write/read different formats. I think I should have said SerializersModule, not JsonBuilder :-)

@pdvrieze I would even happily provide a list of global serializers to the kotlin-serialization plugin in build.gradle as a mapping of KClass -> Serializer, so that it could do it's compile time checking.

Anyway, SerializersModule.reflectiveOrContextual is quite inefficient currently, as it looks for a precompiled serializer using reflection every time. It should cache already found serializers to reuse them more quickly. Maybe this is the reason why kotlin-serialization is actually slower than other Java json libraries.

These two issues stop me from using the library, unfortunately. Back to Jackson that doesn't support inline classes properly...

@pdvrieze
Copy link
Contributor

@angryziber What are you trying to achieve here? In particular, why are you using reflective or contextual serialization. The library is really designed for statically determining the serializer. However, it is reasonable that the lookup could be configured to use caching.

@angryziber
Copy link

@pdvrieze static serialization sounds good to me, but I want to avoid defining custom serializers for useful 3rd-party classes over and over again in every class/file. This is a serious violation of DRY principle. I want to do it once per my gradle project.

Contextual kind of works for this purpose, but it still requires writing @contextual everywhere and it's actual purpose is different - dynamic, but global definition of static serializers is needed.

@christophsturm
Copy link

is there any progress on this? either that or more built in serializers (for example BigDecimal, OffsetDateTime) would be really useful.

@sandwwraith
Copy link
Member

@christophsturm No, this feature is postponed

@Gaming32
Copy link

Gaming32 commented Sep 3, 2022

I feel that a config option could be added in the build.gradle(.kts).

@angryziber
Copy link

@sandwwraith just a reminder that kolinx-serialization without this feature is unusable for a lot of developers on the JVM

@Kantis
Copy link
Contributor

Kantis commented Apr 27, 2023

Shameless plug! I feel my project, KotlinX Serialization Standard Serializers, solves these ergonomic issues by providing readily defined typealiases and serializers for many common JVM types (and adding more is welcome!)

The original sample would simply become the following, with no further configuration or definition of serializers required.

data class Foo(val decimal: BigDecimalAsDouble, val id: UuidAsString, val date: LocalDateTimeAsString)

Project status is currently listed as alpha but from my experience using it for the past half year it's been working well for the use-cases I've had.

@ge0ffrey
Copy link

ge0ffrey commented Jan 3, 2024

The lack of java.time serializers out of the box makes it hard to demonstrate our open source library in Kotlin (in Kotlin Notebooks specifically).
(Note that kotlinx.datetime is too weak for us, as it lacks the concept of Duration to represent the time between two LocalTime instances)

@sandwwraith
Copy link
Member

@ge0ffrey I believe that LocalTime arithmetic is intentionally omitted from kotlinx-datetime for the same reason as LocalDateTime — it is hard to do it correctly when accounting for DST gaps and overlaps: https://github.com/Kotlin/kotlinx-datetime?tab=readme-ov-file#date--time-arithmetic. Therefore, a conversion to Instant is recommended.

Regarding java.time serializers, I believe that we can repurpose corresponding kotlinx-datetime serializers in some point of future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Static modules Request for serializer that can be added to Java module
Projects
None yet
Development

No branches or pull requests