81

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.

Vikas Prasad
  • 3,163
  • 5
  • 28
  • 39
DArkO
  • 15,880
  • 12
  • 60
  • 88
  • Duplicate: http://stackoverflow.com/questions/8560348/different-names-of-json-property-during-serialization-and-deserialization/8560390#8560390 – DRCB Oct 24 '13 at 11:51

4 Answers4

130

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.

David Waller
  • 3,057
  • 4
  • 27
  • 28
Vikas Prasad
  • 3,163
  • 5
  • 28
  • 39
  • Didn't cehck whether the actual field name still gets accepted after defining aliases. If so, even `@JsonAlias({"cover_asset"}) private Asset asset` should work. – Vikas Prasad Dec 01 '17 at 10:54
  • 1
    This is a much nicer and concise solution but only available in 2.9 – comiventor Jan 11 '18 at 17:50
  • 8
    The default name issupported, so in this case you only need to specify `"cover_asset"`. – Coltin Jun 19 '18 at 17:50
51

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));

    }
}
whaley
  • 16,075
  • 10
  • 57
  • 68
  • I have a question here - why the other setter method (setMediaAsset()) is private ? – naresh goty Aug 31 '16 at 17:13
  • 1
    @nareshgoty such that the public API of Media is kept simple. There's no good reason to expose two setter methods for the same property. The private method only exists for Jackson to call. – whaley Mar 08 '17 at 15:33
  • @nareshgoty Basically in a way you will see only one property in the response json which i think you want to acheive. In this case you will get "asset":"" – SinhaOjas Jul 20 '17 at 06:04
9

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.

Robocide
  • 6,353
  • 4
  • 37
  • 41
  • Do you need the `"asset"` alias in this example? – riddle_me_this Jun 18 '20 at 15:27
  • 3
    Works well, thanks! Note you don't have to duplicate name in alias. `@JsonAlias({"asset","amazing_asset"})` is enough to cover all three of them (`"asset", "cover_asset","amazing_asset"`). – Micer Apr 02 '21 at 07:10
8

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

Community
  • 1
  • 1
DRCB
  • 2,111
  • 13
  • 21
  • 1
    I saw that but i am trying to avoid this completely. Handling as 2 different things when in fact it is just "asset". Its true however that it gets me a step closer to what i want to achieve. – DArkO Oct 24 '13 at 12:00