9

Using Jackson 2, I'm looking for a generic way to be serialize objects as a single value (then serialize them back later populating only that single field) without having to repetitively create a JsonSerializer / JsonDeserializer to handle each case. The @JsonIdentityInfo annotation comes pretty close but misses the mark a little bit since, as far as I can tell, it will always serialize the full child object on the first occurrence.

Here is an example of what I want to do. Given the classes:

class Customer {

    Long id = 99;
    String name = "Joe"; 
    // Lots more properties
}

class Order {
    String orderNum = "11111"
    @WhateverAnnotationsINeedHereToDoWhatIWant
    Customer customer;
}

I would like Order to serialize as either (either would be perfectly acceptable to me):

{"orderNum":"11111", "customer":"99"}
{"orderNum":"11111", "customer":{"id":99}}

What @JsonIdentityInfo does makes it more difficult to deal with on the client-side (we can assume that the client knows how to map the customer ID back into the full customer information).

@JsonIgnoreProperties could also come pretty close for the second JSON shown but would mean I would have to opt-out of everything but the one I want.

When I deserialize back I would just want the Customer to be initialzed with the "id" field only.

Any magic way to do this that I'm missing without getting into the soupy internals of Jackson? As far as I can tell, JsonDeserializer/JsonSerializer has no contextual information on the parent so there doesn't seem to be an easy way to create a @JsonValueFromProperty("id") type Jackson Mix-in then just look at that annotation in the custom Serializer/Deserializer.

Any ideas would be greatly appreciated. Thanks!

jonc
  • 795
  • 1
  • 7
  • 14

2 Answers2

8

I once needed fine-grained control over the JSON returned per different type of request, and I am afraid I ended up using custom Serializers and Deserializers.

A simple alternative would be adding @JsonIgnore to the Customer field of Order and add the following getter to Order:

@JsonProperty("customer")
public Long getCustomerId(){
  if (customer != null){
    return customer.getId();
  }
  else {
    return null;
  }
}

The returned JSON would then be:

{"orderNum":"11111", "customer":"99"}
Integrating Stuff
  • 5,253
  • 2
  • 33
  • 39
  • Thanks Integrating Stuff! That simple solution actually seems pretty workable for me, and seems horrible obvious now ;). In the absence of a @JsonIgnorePropertiesExcept("id") annotation, I think that'll do just fine. – jonc Aug 23 '12 at 18:40
4

Another possibility could be use of @JsonValue, used on id field.

Jackson 2.1 will add a feature to force serialization of even the force reference as id (by new property, "firstAsId" for @JsonIdentityInfo). That may not work well with deserialization for all cases but perhaps would work for you.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Thanks StaxMan. Unfortunately @JsonValue wouldn't really solve the problem since, if I was only serializing Customer on its own, I would expect the record to be fully serialized. – jonc Sep 14 '12 at 21:38
  • 1
    Ok. Your best bet then is Jackson 2.1 -- it will allow separation of references (which always use id) from serialization of the type. – StaxMan Sep 14 '12 at 21:46
  • 4
    Finally for around to trying out 2.1 since it was released in October :).@JsonIdentityReference(alwaysAsId = true) and @JsonIdentityInfo(generator="generator = ObjectIdGenerators.PropertyGenerator.class") works great from the Serialization end, but not so well when it comes time to deserialize since it can't resolve the Object ID reference. It would work with JPA providers to just instantiate an empty object and set only the ID for deserialization but unsure how I might be able to coerce the jackson deserializer to do this without defining a custom deserializer for each possible reference type – jonc Dec 05 '12 at 21:30
  • 2
    Right, you would need to add code that figures out where to populate actual instance. – StaxMan Dec 06 '12 at 03:37
  • 1
    @jonc Did you ever figure out how to do this? I am having trouble deserializing my collections as well when using JsonIdentityreference. – testing123 Jun 12 '13 at 04:19
  • 1
    Hey @testing123. Sorry, I'm not using JsonIdentityReference to avoid de-serialization headaches. If you come up with or find a good solution, let me know; I'd still be interested. – jonc Jun 13 '13 at 20:05