How does Spring ObjectMapper handle serializing an...
# spring
l
How does Spring ObjectMapper handle serializing an Enum? That is, how can I ensure that it round-trips to the enum’s single associated value, not to the stringified version of the Enum name itself?
k
By "single associated value" do you mean the ordinal? Why do you think this is less error-prone than the name?
l
Because I am converting a bunch of arbitrary string values to an enum, and need to keep the serialized version exactly the same. But the enum cases are capitalized.
Right now I have this, and am not sure if it’s the best way:
Copy code
enum class AvailabilityReasonCode(val string: String) {
    Match("match"),
    Character("character"),
    Error("error"),
    // ...
}
a
Annotate the @Entity that contains the Enum with
Copy code
@Enumerated(EnumType.ORDINAL)
or
Copy code
@Enumerated(EnumType.STRING)
It defaults to ORDINAL as I recall
l
Would string be the stringified name, or the string value? Because I need to keep the capitalization to not break an API. 🙂
It’s also not an entity, just a DTO.
r
If case sensitivity is the only issue, there is a Jackson ObjectMapper setting called ACCEPT_CASE_INSENSITIVE_ENUMS that can be set to
true
, otherwise you could also annotate the
string
property with
@JsonValue
🙌 1
a
It would serialize the Enum text name, so
Match
or
Error
. Though I typically use all caps for enum values.
l
This is for sending. I won’t be receiving this message. And… I don’t know that I can modify the global ObjectMapper configuration. For the annotation, that would be something like:
Copy code
enum class AvailabilityReasonCode(
  @JsonValue
  val string: String
) {
    Match("match"),
    Character("character"),
    Error("error"),
    // ...
}
?
a
Seems like if you serialize that to JSON you will send
match
Not
Match
But the DB will store a
0
r
@Larry Garfield Yes, out of the top of my head I don't recall whether the annotation needs to be on the getter or on the field (so it might need to be
@get:JsonValue
instead), but I would try your version first
l
In this case it won’t end up in a DB. I just want to send a JSON blob with
match
in it, while using
Availability::Match
in code.
Hm, no, still getting a capitalized value.
a
If the Enum is part of a DTO you may want to place it behind a delegate and serialize the
string
value yourself
r
Did you try
@get:JsonValue
as well?
l
Trying that now.
Still capitalized.
r
Hmm weird, are you using an old version of Jackson? This should be the correct way, see e.g. https://www.baeldung.com/jackson-serialize-enums#3-enums-and-jsonvalue (That link also provides some alternatives)
k
I would have expected
@get:JsonValue
to work. Try using JsonProperty:
Copy code
enum class AvailabilityReasonCode {
    @JsonProperty("match") Match,
    @JsonProperty("character") Character,
    @JsonProperty("error") Error,
    // ...
}
(Also, as Riccardo says, use a recent version of Jackson)
l
Still getting a capital…
Our build.gradle.kts file doesn’t specify a Jackson version, so… I presume it’s up to date?
k
It would be best to check using the External Libraries section of the Project window in IntelliJ IDEA. The latest is 2.17.2.
l
Looks like we’re on 2.17.1. So should be close enough.
Having a method with @JsonValue on it doesn’t work, either. 😞
Ugh. I was hoping to avoid having to do this manually…
OK, I gave in and setup some manual mapping. I was already converting a wrapping object from an internal to external format, so I just added more logic there to do the same and serialize manually. Not ideal, but it works and lets me move on. Thanks folks.
🥲 2
105 Views