Reputation: 104
I'm new to Spring-boot and am trying to deserialize json array into java String using Jackson in a Spring-boot Application. Something like
{"history": ["historyA", "historyB"]} (JSON Request Body) -> String history;
However, the following error message got logged.
Cannot deserialize instance of `java.lang.String` out of START_ARRAY token
My Controller is similar to
@RestController
public class PatientController {
@PostMapping
public void create(@RequestBody @Valid Patient patient) {
mapper.create(patient);
}
}
My POJO is similar to:
@Data
@NoArgsConstructor
public class Patient {
@JsonDeserialize(contentUsing = PatientHistoryDeserializer.class, contentAs = List.class)
private String history;
My Json Deserializer is similar to:
public class PatientHistoryDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
List<String> histories = new LinkedList<>();
if (p.getCurrentToken() == JsonToken.START_ARRAY) {
while (p.getCurrentToken() != JsonToken.END_ARRAY) {
String history = p.getValueAsString();
if(history.contains("#"))
throw new ClientError(HttpServletResponse.SC_BAD_REQUEST, "invalid...");
histories.add(history);
}
}
return String.join("#", histories);
}
}
Is my goal achievable ? Or any suggestions on how to convert as I wanted ?
Upvotes: 1
Views: 4002
Reputation: 2890
This can be done like this
public class PatientHistoryDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
if (jsonParser.currentToken() == JsonToken.START_ARRAY) {
List<String> histories = new ArrayList<>();
jsonParser.nextToken();
while (jsonParser.hasCurrentToken() && jsonParser.currentToken() != JsonToken.END_ARRAY) {
histories.add(jsonParser.getValueAsString());
jsonParser.nextToken();
}
return String.join("#", histories);
}
return null;
}
}
And usage would like
@JsonDeserialize(using = PatientHistoryDeserializer.class)
String histories;
The purpose of contentUsing
and contentAs
are a bit different than the use case here. let's take the following example.
class Histories {
Map<String, String> content;
}
and JSON is something like this
{"content": { "key" : ["A","B"]}}
and you want to deserialize this into a map having (key = "A#B")
there are two ways to do it, write custom deserializer or use contentUsing
attribute to specify how your values should be deserialized
@JsonDeserialize(contentUsing = PatientHistoryDeserializer.class)
Map<String, String> content;
Similarly, you can use other annotation attributes like keyUsing
for keys for maps.
Upvotes: 2