JSON Jackson parse different keys into same field

I have a POJO which has a field:

public class Media {
private Asset asset;
}

Everything works perfectly when parsing a json response into this asset POJO. but however there is a slight difference with the key this asset comes with. It can either be:

  @JsonProperty("cover_asset")

or

  @JsonProperty("asset")

Is there a way to annotate the POJO to recognize this case and de-serialize into the same field. Its not possible for both of them to appear in the same response.

77529 次浏览

I'd propose to use getters/setters, for both property names, which are referring to the same POJO field.

public class Media {
private Asset asset;


@JsonProperty("cover_asset")
public Asset getCoverAsset() {
return asset;
}


public void setCoverAsset(Asset asset) {
this.asset= asset;
}


@JsonProperty("asset")
public Asset getAsset() {
return asset;
}


public void setAsset(Asset asset) {
this.asset= asset;
}
}

See also my answer to possible duplicate question: Different names of JSON property during serialization and deserialization

More succinctly, I would suggest using two separate @JsonSetter annotations for this. Here's a working example. This means that your java class will only have one getter method to use for the property instead of two. You can also make the setter you don't want exposed to clients of Media private and treat one of the json keys in a special manner.

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.ObjectMapper;


@SuppressWarnings("unused")
public class Media {


private Asset asset;


@JsonGetter("asset")
public Asset getAsset() {
return asset;
}


@JsonSetter("asset")
public void setAsset(Asset asset) {
this.asset = asset;
}


@JsonSetter("cover_asset")
private void setMediaAsset(Asset asset) {
if (this.asset == null) {
setAsset(asset);
}
}




private static class Asset {
@JsonProperty("foo")
private String foo;
}


public static void main(String[] args) throws Exception {
String withAsset = "{'asset': {'foo':'bar'}}";
String withCoverAsset = "{'cover_asset': {'foo':'bar'}}";


ObjectMapper mapper = new ObjectMapper();
Media mediaFromAsset = mapper.readValue(withAsset.replace('\'','"'), Media.class);
Media mediaFromCoverAsset = mapper.readValue(withCoverAsset.replace('\'','"'), Media.class);


System.out.println(mediaFromAsset.asset.foo.equals(mediaFromCoverAsset.asset.foo));


}
}

Well, as only deserialization is your concern, @JsonAlias introduced in 2.9 is perfect for this situation. You can do something like this:

@JsonAlias({"cover_asset", "asset"})
private Asset asset;

@JsonAlias docs:

Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name. Alias information is also exposed during POJO introspection, but has no effect during serialization where primary name is always used.

Note: Make sure you update all related dependencies(annotations, core, databind) if you are using them. Updating just annotations without others threw me runtime error.

Great answer By Vikas with JsonAlias.

Just adding that you can also benefit from both of the worlds (JsonProperty&Alias) [Since jackson 2.9]:

@JsonProperty("cover_asset")
@JsonAlias({"asset", "cover_asset","amazing_asset"})
private Asset asset;

Reference.