I have a REST API which returns a JSON response as:
{
"channel" : "JHBHS"
}
and sometimes it returns:
{
"channel": {
"id": 12321,
"name": "Some channel"
}
}
I have a POJO like:
public class Event {
private String channel;
@JsonProperty("channel")
private Channel channelObj;
}
public class Channel {
private int id;
private String name;
}
So, is there a way (other than writing your own custom deserializer) in Jackson2 which will help me map channel
in JSON to String
type when it's a String
and Channel
type when it's a JSON Object?
Or in other words, is there a way in Jackson which maps by type
of the variable and not just by name
?
@JsonProperty can change the visibility of logical property using its access element during serialization and deserialization of JSON. @JsonAlias defines one or more alternative names for a property to be accepted during deserialization.
ObjectMapper is the most important class in Jackson API that provides readValue() and writeValue() methods to transform JSON to Java Object and Java Object to JSON. ObjectMapper class can be reused and we can initialize it once as Singleton object.
@JsonProperty is used to mark non-standard getter/setter method to be used with respect to json property.
Default typing is a mechanism in the Jackson ObjectMapper to deal with polymorphic types and inheritance. If you want to deserialize JSON to a Java POJO but are unsure what subtype the object or the field is, you can simply deserialize to the superclass.
I can suggest you to use JsonNode like this:
class Event {
@JsonProperty("channel")
private JsonNode channelInternal;
private Channel channel;
private String channelStr;
/**
* Custom getter with channel parsing
* @return channel
*/
public Channel getChannel() {
if (channel == null && channelInternal != null) {
if (channelInternal.isObject()) {
int id = channelInternal.get("id").intValue();
String name = channelInternal.get("name").asText();
channel = new Channel(id, name);
}
}
return channel;
}
/**
* Custom getter with channel string parsing
* @return channel string
*/
public String getChannelStr() {
if (channelStr == null && channelInternal != null) {
if (channelInternal.isTextual()) {
channelStr = channelInternal.asText();
}
}
return channelStr;
}
}
or like this:
class Event {
private Channel channel;
private String channelStr;
@JsonSetter("channel")
public void setChannelInternal(JsonNode channelInternal) {
if (channelInternal != null) {
if (channelInternal.isTextual()) {
channelStr = channelInternal.asText();
} else if (channelInternal.isObject()) {
int id = channelInternal.get("id").intValue();
String name = channelInternal.get("name").asText();
channel = new Channel(id, name);
}
}
}
public Channel getChannel() {
return channel;
}
public String getChannelStr() {
return channelStr;
}
}
But I think using custom deserializer is more common.
Here is test code
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String source1 = "{\n" +
" \"channel\" : \"JHBHS\"\n" +
"}";
String source2 = "{\n" +
" \"channel\": {\n" +
" \"id\": 12321,\n" +
" \"name\": \"Some channel\"\n" +
" }\n" +
"}";
//Test object parsing
Event result = objectMapper.readValue(source2, Event.class);
System.out.println(String.format("%s : %s", result.getChannel().getId(), result.getChannel().getName()));
//Test string parsing
result = objectMapper.readValue(source1, Event.class);
System.out.println(result.getChannelStr());
}
And the output:
12321 : Some channel
JHBHS
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With