QUESTION: How do I capture the (optional) List field media_links_txt
from the received JSON as either null or its actual value with concise/idiomatic modern Java?
Functional wishes are:
@JsonGetter
and @JsonSetter
fieldnames since the Record is used both as deserialization target and response model (API clients demand different field names as incoming JSON)optionalStuff
field is ... well optionally present in deserialization flowCode is as follows:
import com.fasterxml.jackson.annotation.*;
import org.springframework.lang.NonNull;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public record TestResponse(@NonNull Response response) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Response(@NonNull List<Doc> docs,
@NonNull Integer numFound,
@NonNull Integer start) {
public record Doc(@NonNull String id,
@NonNull @JsonGetter("content_t") @JsonSetter("content") String content,
@NonNull @JsonGetter("title_t") @JsonSetter("title") String title,
@JsonGetter("media_links_txt") @JsonSetter("mediaLinks") List<String> mediaLinks) {
}
}
}
When this code receives JSON that looks like this:
{
"response" : {
"docs" : [ {
"content_t" : "Test content 1",
"title_t" : "Test title 1",
"media_links_txt" : [ "d7810883-42de-4280-a286-5bb14e517ce3", "fa60db0a-0e28-4c9c-8092-4eafe57251cd" ],
"id" : "54870dc265c855c516bcd0a2f93f2267"
}, {
"content_t" : "Test content 2",
"title_t" : "Test content 2",
"id" : "a4a38aa64427d63aab0c4412eb659586"
} ],
"numFound" : 2,
"start" : 0
}
It errors with the following message:
Should never call set() on setterless property
and points towards media_links_txt
. This confuses me ...
null
value for mediaLinks
is what I think I have written)docs
field (also a List) without problem?So I tried to trick it with the following code (maybe it required a non-default type)
import com.fasterxml.jackson.annotation.*;
import org.springframework.lang.NonNull;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public record TestResponse(@NonNull Response response) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Response(@NonNull List<Doc> docs,
@NonNull Integer numFound,
@NonNull Integer start) {
public record Doc(@NonNull String id,
@NonNull @JsonGetter("content_t") @JsonSetter("content") String content,
@NonNull @JsonGetter("title_t") @JsonSetter("title") String title,
@JsonGetter("media_links_txt") @JsonSetter("mediaLinks") List<StringClone> mediaLinks) {
public record StringClone(@NonNull String mediaLinksRetry) {
}
}
}
}
Which throws:
Cannot construct instance of StringClone (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('d7810883-42de-4280-a286-5bb14e517ce3')
QUESTION: How do I capture the (optional) List field media_links_txt
from the received JSON as either null or its actual value with concise/idiomatic modern Java?
Used versions are:
I think https://github.com/FasterXML/jackson-databind/issues/2692 might describe the issue, but no proper workaround as of yet.
The value parameter in your JsonSetter
s needs to match the field name in the JSON. I assume Jackson recognises that the type is a record and is able to call the constructor if the ctor parameter names line up with the JSON field names.
I.e., f you change the JsonSetter
annotations like this:
public record Doc(String id,
@JsonGetter("content_t") @JsonSetter("content_t") String content,
@JsonGetter("title_t") @JsonSetter("title_t") String title,
@JsonGetter("media_links_txt") @JsonSetter("media_links_txt") List<String> mediaLinks) {
}
then it seems to work, at least it does for me. This can be further simplified by replacing the JsonGetter
/JsonSetter
pairs with a single JsonProperty
annotation:
public record Doc(String id,
@JsonProperty("content_t") String content,
@JsonProperty("title_t") String title,
@JsonProperty("media_links_txt") List<String> mediaLinks) {
}