-
-
Notifications
You must be signed in to change notification settings - Fork 177
Improvements to serialization of value class
.
#527
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
8d80860
add ValueClassBoxSerializer
k163377 db939c7
add findeSerializer
k163377 19c5c02
added consideration for cases where the value wrapped by value class …
k163377 2de548a
add test
k163377 e4fd10d
add failing test
k163377 eb38c62
add CREDITS
k163377 1660b94
fix generics
k163377 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/GitHub524.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.fasterxml.jackson.module.kotlin.test.github | ||
|
||
import com.fasterxml.jackson.core.JsonGenerator | ||
import com.fasterxml.jackson.databind.SerializerProvider | ||
import com.fasterxml.jackson.databind.annotation.JsonSerialize | ||
import com.fasterxml.jackson.databind.module.SimpleModule | ||
import com.fasterxml.jackson.databind.ser.std.StdSerializer | ||
import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder | ||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper | ||
import org.junit.Test | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertNotEquals | ||
|
||
// Most of the current behavior has been tested on GitHub464, so only serializer-related behavior is tested here. | ||
class GitHub524 { | ||
@JvmInline | ||
value class HasSerializer(val value: Int?) | ||
class Serializer : StdSerializer<HasSerializer>(HasSerializer::class.java) { | ||
override fun serialize(value: HasSerializer, gen: JsonGenerator, provider: SerializerProvider) { | ||
gen.writeString(value.toString()) | ||
} | ||
} | ||
|
||
@JvmInline | ||
value class NoSerializer(val value: Int?) | ||
|
||
data class Poko( | ||
// ULong has a custom serializer defined in Serializers. | ||
val foo: ULong = ULong.MAX_VALUE, | ||
// If a custom serializer is set, the ValueClassUnboxSerializer will be overridden. | ||
val bar: HasSerializer = HasSerializer(1), | ||
val baz: HasSerializer = HasSerializer(null), | ||
val qux: HasSerializer? = null, | ||
// If there is no serializer, it will be unboxed as the existing. | ||
val quux: NoSerializer = NoSerializer(2) | ||
) | ||
|
||
@Test | ||
fun test() { | ||
val sm = SimpleModule() | ||
.addSerializer(Serializer()) | ||
val writer = jacksonMapperBuilder().addModule(sm).build().writerWithDefaultPrettyPrinter() | ||
|
||
// 18446744073709551615 is ULong.MAX_VALUE. | ||
assertEquals( | ||
""" | ||
{ | ||
"foo" : 18446744073709551615, | ||
"bar" : "HasSerializer(value=1)", | ||
"baz" : "HasSerializer(value=null)", | ||
"qux" : null, | ||
"quux" : 2 | ||
} | ||
""".trimIndent(), | ||
writer.writeValueAsString(Poko()) | ||
) | ||
} | ||
|
||
class SerializeByAnnotation(@get:JsonSerialize(using = Serializer::class) val foo: HasSerializer = HasSerializer(1)) | ||
|
||
@Test | ||
fun failing() { | ||
val writer = jacksonObjectMapper().writerWithDefaultPrettyPrinter() | ||
|
||
// JsonSerialize is not working now. | ||
assertNotEquals( | ||
""" | ||
{ | ||
"foo" : "HasSerializer(value=1)" | ||
} | ||
""".trimIndent(), | ||
writer.writeValueAsString(SerializeByAnnotation()) | ||
) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this actually work as expected? Call should only be made if the value class itself is
null
; not for wrapped value. I may be wrong since I am not familiar with types here, just suggest validation of all cases.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the property itself is
null
, the return value from thejava getter
will be in anunboxed
state, so theValueClassBoxSerializer
will not be used.This is verified by the following comparison.
https://github.com/FasterXML/jackson-module-kotlin/pull/527/files#diff-7c6b0a8c396b759fd146df36577c7a8fb3cbe94406e6912a729f6e028413411bR49-R51
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. As long as unit tests cover expected behavior it's probably fine.
One other note: "null serializer" is only ever used for writing
null
value or placeholder, and never anything more advanced. So one typically returns sort of special constant value serializing implementation, instead of delegating.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cowtowncoder @tatu-at-datastax
Sorry if I'm not reading this correctly.
The
findNullSerializer
returns a serializer for values that arenon-null
inKotlin
.I meant to add a comment to explain that.
I think it might have been better to have a
private
function named something likefindSerializerForValueClass
and call the same function infindSerializer
/findNullSerializer
.If you have any comments or implementations that are easier to understand, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is simply this: method
findNullSerializer
is called by Jackson only EVER when there is a literal JVM-levelnull
to serialize. Regular serializers are NEVER givennull
values to serialize; they are not expected to (have to) do null checks, nor know what to serialize.In that sense it seems/seemed odd that implementation would delegate to
findSerializer()
: I am not sure why this is done. It seems rather like it should not be defined at all.But then again Kotlin module sometimes overrides things I do not expect it to, partially since null handling in Kotlin is quite different from plain Java.
I'll let you and Kotlin module owners decide here what to do; I just try to give input from Jackson databind side to help develop things :)