1

I have a POJO which is used for mapping the values received from rabbitmq. The messages are sent from other third-party services which I don't have control over. The problem is that these services don't send the certain fields in a consistent manner.

For example, in the case of an error field, this field will only have information when the third-party service wants to send a message to inform that there is an error. Some services may send in their JSON message to the queue this way:

{
   id: 123,
   name: "PersonA",
   error: null
}

And then there are also services that may send their JSON message this way:

{
   id: 123,
   name: "PersonA",
   error: []
}

And there are also services that may just omit the field entirely:

{
   id: 123,
   name: "PersonA"
}

Of course, if there is an error, that error field will contain fields within it:

{
   id: 123,
   name: "PersonA",
   error: {
      message: "Cannot find PersonA"
   }
}

So, there is a chance that the error field can be null, undefined, array or an object. The problem is, I can only define a single type in my POJO for the error field.

public class MyMessage {
    private int id;
    private MessageError error;
    private String name;

    @JsonCreator
    public MyMessage(
        @JsonProperty("id") int id,
        @JsonProperty("error") MessageError error,     // error is a MessageError object already but what is sent in could be null, undefined, an array or an object
        @JsonProperty("name") String name
    ) {
        this.id = id;
        this.error = error;
        this.name = name;
    }
}

public class MessageError {
    private String message;

    @JsonCreator
    public MessageError(
        @JsonProperty("message") String message
    ) {
        this.message = message;
    }
}

I'm using Spring with Jackson. In this case, how can I handle and map all the possible values that maybe assigned to the error field in the message to the POJO when it gets deserialised?

Carven
  • 14,988
  • 29
  • 118
  • 161

2 Answers2

0

If you don't have any markers in the json data to identify its source and thus its shape, I would try to set error field type to object, and if it doesn't work or fit, to "json raw" as explained in answers of How can I include raw JSON in an object using Jackson? So you can proceed the error field in the appropriate way according to the content you would discover at runtime, peeking from expected ones you detailed above.

Michael Zilbermann
  • 1,398
  • 9
  • 19
0

The simplest way to resolve this problem is to define error field as a common Object type

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"id",
"name",
"error"
})
public class MyMessage {

@JsonProperty("id")
private int id;
@JsonProperty("name")
private String name;
@JsonProperty("error")
private Object error;

@JsonProperty("id")
public int getId() {
return id;
}

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

@JsonProperty("name")
public String getName() {
return name;
}

@JsonProperty("name")
public void setName(String name) {
this.name = name;
}

@JsonProperty("error")
public Object getError() {
return error;
}

@JsonProperty("error")
public void setError(Object error) {
this.error = error;
}

}

And then you have to map it to another DTO:

// someplace where you will map it

MyMessage message = source.getMessageFromQueue();

if(message.getError() == null) {
  // do something
} else {
   Object error = message.getError();
   handleError(error);
}

private void handleError(Object error) {
   if(error instanceOf MessageError) {
       handleMessageError((MessageError) error) // handle as known MessageError object 
   } else if(error instanceOf String) {
       handleStringError((String) error) // handle as String, write in logs maybe
   } else if(error instanceOf List) {
       handleErrors((String) error) // handle as List errors
   } else {
       handleUndefinedError()
   }
}
Scrobot
  • 1,911
  • 3
  • 19
  • 36