2
votes

I have a situation where I am passing back n forth an object from Java to Javascript client and it's being serialized by the built in Jackson mapper in Spring 3 (using the @RequestBody / @ResponseBody and application/json content type)

The problem I have is some classes implement from an interface which has a getter but no setter.

I do want the getter value available from the client side so I cannot use @JsonIgnore annotation because then it ignores the property entirely, both serializing and deserializing. I need the property when serialized.

Any other way to do this?

2
how would you deserialize the property value without a setter in the class?eis
I wouldnt care about it on deserialization. it can be ignored when deserializing.Trant
hmm... but you're saying "I do want the getter value available from the client side" - so it's available in the json that client javascript sents you and you need the value, doesn't this mean that you do need it when you deserialize (JSON -> java) but not when you serialize (Java -> JSON)?eis
I need it in Javascript going Java>JSON, I dont care for it coming back JSON>Java.Trant

2 Answers

2
votes

There is probably an easier way, but I thought to mention the usage of JSON views as a possible solution. There's an example on this thread.

You might need a different view on deserialization and not just on serialization, and that would be a Jackson 2.0 feature - supported by Spring 3.2 and backported into Spring 3.1. Using a view on serialization only is a feature since Jackson 1.4.

Another option that comes to mind is using a custom deserializer.

0
votes

I was looking for the same thing.

According to the Jackson docs, we can set a @JsonIgnore annotation on a property, getter or setter and that would hide the complete property, unless we give the setter a @JsonProperty annotation that would make sure this property is visible when setting it. Unfortunately, that doesn't work the other way around. I wanted to show the property in my response, but not include it in my request.

Use case is an auto generated id for example. I don't want the user to set, or even see that, but he may read it.

You can achieve this by hiding the attribute itself indeed and then add a @JsonAnyGetter method. In this method you can massage the data to any form you want. It's also useful to represent complex attribute classes of which you only want to show a single name or identifier or other formatting. There are better ways of doing the latter, but if the use case is not too complex, this suffices.

So as example (My apologies if this is too elaborate):

User:

public class User {

    private String uid;
    private String customerId;
    private String taxSsnId;

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getCustomerId() {
        return extCustomerId;
    }

    public void setCustomerId(String extCustomerId) {
        this.extCustomerId = extCustomerId;
    }

    public String getTaxSsnId() {
        return taxSsnId;
    }

    public void setTaxSsnId(String taxSsnId) {
        this.taxSsnId = taxSsnId;
    }

    @JsonIgnore
    public void getId(){
        if (getUid() != null){
            return getUid();
        }
        if (getCustomerId() != null ){
            return getCustomerId();
        }
        return null;
    }
}

Setting:

public class Setting {

    @JsonIgnore
    private int id;

    private String key;
    private String value;

    @JsonIgnore
    private User lastUpdatedBy;

    @JsonIgnore
    private Date lastUpdatedAt;

        public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public User getLastUpdatedBy() {
        return lastUpdatedBy;
    }

    public void setLastUpdatedBy(User lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }

    public Date getLastUpdatedAt() {
        return lastUpdatedAt;
    }

    public void setLastUpdatedAt(Date lastUpdatedAt) {
        this.lastUpdatedAt = lastUpdatedAt;
    }

    @JsonAnyGetter
    private Map<String, String> other() {
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put( "id", this.getId());
        map.put( "lastUpdatedBy", this.getLastUpdatedBy().getId());
        SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
        map.put( "lastUpdatedAt", format.format(this.getLastUpdatedAt()) );
        return map;
    }

}

Yields this Request schema (de-serialization view):

{
  "key": "string",
  "value": "string"
}

and this Response schema (serialized view):

{
  "key": "string",
  "value": "string",
  "id": "12345",
  "lastUpdatedBy": "String",
  "lastUpdatedAt": "String" 
}