Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON Deserialization from ID into Object

To make sure the data being sent back and forth isn't redundant in my RESTful web service, every nested object only has it's ID serialized (A Message's User creator only has userId serialized since both the client and server will already know all the details of the user).

Serialization works perfectly, producing this:

{"messageCreatorUser":"60d01602-c04d-4a3f-bbf2-132eb0ebbfc6","messageBody":"Body", ...}

Problem: Deserialization does not produce a nested object with only its ID. The resulting deserialized nested object is null.

Here are the previously mentioned Message and User objects. Serialization "strategy" was used from the 3rd option specified here: How to serialize only the ID of a child with Jackson.

Message.java

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "messageId")
public class Message implements Serializable {

    // -- Hibernate definitions omitted --
    private UUID messageId;

    // -----------------------------------------------------------------
    // Here is what makes the serializer print out the ID specified on the class definition

    @JsonIdentityReference(alwaysAsId = true)

    // Here is my attempt to get the User class back when I deserialize

    @JsonDeserialize(as = User.class)
    @JsonSerialize(as = User.class)

    private User messageCreatorUser;
    // ------------------------------------------------------------------


    // -- more arbitrary properties --

    public Message() {
    }

    public Message(UUID messageId) {
        this.messageId = messageId;
    }

    public Message(String messageId) {
        this.messageId = UUID.fromString(messageId);
    }

    // -- getters and setters --

User.java

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User implements Serializable {

    private UUID userId;

    // -- other arbitrary properties -- 

    public User() {
    }

    public User(UUID userId) {
        this.userId = userId;
    }

    public User(String userId) {
        this.userId = UUID.fromString(userId);
    }

    // -- getters and setters --

Expected deserialized object:

Message object =
     String messageBody = "Body";
     User messageCreatorUser =
         UUID userId = 60d01602-c04d-4a3f-bbf2-132eb0ebbfc6;

Actual deserialized object:

Message object =
     String messageBody = "Body";
     User messageCreatorUser = null;

Like I said, I was hoping for a nested User object to be created with only the ID of 60d01602-c04d-4a3f-bbf2-132eb0ebbfc6

Using:

  • Wildfly 10.0.Final:
    • RESTEasy 3.0.15.Final
    • RESTEasy Jackson 2 Provider 3.0.15.Final
      • Jackson 2.6.3 (annotations, core, databind, etc)

Why do the results differ?

like image 700
Kevin Thorne Avatar asked Jul 18 '16 17:07

Kevin Thorne


1 Answers

As the answer here (Jackson deserialize JsonIdentityReference (alwaysAsId = true)) states, using a setter deserializer works well and does not require an obnoxious custom deserializer:

Message.java

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "messageId")
    public class Message implements Serializable {

        private UUID messageId;

        @JsonIdentityReference(alwaysAsId = true)
        private User messageCreatorUser;

        // -- other fields and such --

        public User getMessageCreatorUser() {
            return messageCreatorUser;
        }

        public void setMessageCreatorUser(User messageCreatorUser) {
            this.messageCreatorUser = messageCreatorUser;
        }

        @JsonProperty("messageCreatorUser")
        public void setMessageCreatorUser(String userId) {
            this.messageCreatorUser = new User(userId);
        }

User.java

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId")
    public class User implements Serializable {

        private UUID userId;

        // -- other fields --

        public User(String userId) {
            this.userId = UUID.fromString(userId);
        }

    }

Do note that in order to use @JsonIdentityReference(alwaysAsId = true), you need to have the @JsonIdentityInfo(...) somewhere.

like image 163
Kevin Thorne Avatar answered Sep 22 '22 14:09

Kevin Thorne