Reputation: 23
I am retrieving data from an API endpoint that returns data in two different expected json formats. One of the responses is a success response and one of the responses is a failure response. The other endpoints in the API are similar and also have a success and failure format. For most of the endpoints I just deserialize both types of responses into a single Java object where some fields are just set to default/null values when not present. My problem with this endpoint is that the success response is a json array and the fail response is a json object. I have tried everything to have a simple way to deserialize both of these possible responses into a single java object.
Example success json.
[
{
"item1": "somevalue1",
"item2": "somevalue2"
},
{
"item1": "somevalue3",
"item2": "somevalue4"
},
..
..
]
Example fail json
{
"success": false,
"errorMessage": "something went wrong "
}
My Java class I am currently using works to deserialize the success json but not for the fail json.
public class ResponseObject {
public final boolean success;
public final String errorMessage;
public final List<MyItem> items;
@JsonCreator
public ResponseObject(ArrayList<MyItem> items) {
this.items = items;
}
}
And I also have a constructor that works for the fail case but not for the success case
public class ResponseObject {
public final boolean success;
public final String errorMessage;
public final List<MyItem> items;
@JsonCreator
public ResponseObject(@JsonProperty("success") Boolean success, @JsonProperty("errorMessage") String errorMessage){
this.success = success == null;
this.errorMessage = errorMessage;
this.items = items;
}
}
My deserialization code looks something like
ObjectReader objectReader = objectMapper.readerFor(ResponseObject.class);
Object json = objectReader.readValue(inputStream);
Whatever strategy I have tried to be able to deserialize both cases generically seems to fail. If I try to include the json array in the constructor with a @JsonProperty then I have no name/value to refer to the array of items, and the code throws an exception.
What I need is a way to deserialize both responses into the ResponseObject format that I outlined, when I get the success reponse the success field should be true, the errorMessage should be null and the items should contain a list of MyItem. When I get a fail response, the success should be false, the errorMessage should have a string message and the items list should be null.
How can I achieve this? Or, how else can I structure my code to handle multiple expected json formats? I know I could deserialize to a TreeMap, check the format and then convert again to the final object for example, but I would like to skip this intermediate step.
Thanks for any advice that anyone can give me on this one :)
Upvotes: 2
Views: 622
Reputation: 2307
If you add a POJO for the error message, you could add a second JsonCreator to your Response Object.
public class ErrorResponse {
private boolean success;
private String errorMessage;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
Modified ResponseObject with 2 JsonCreator
public class ResponseObject {
public final boolean success;
public final String errorMessage;
public final List<MyItem> items;
@JsonCreator
public ResponseObject(List<MyItem> items) {
this.success = true;
this.errorMessage = null;
this.items = items;
}
@JsonCreator
public ResponseObject(ErrorResponse error){
this.success = error.isSuccess();
this.errorMessage = error.getErrorMessage();
this.items = null;
}
}
Upvotes: 0
Reputation: 1764
You can try to make a superclass
public class ResponseObject {
public final boolean success;
public final String errorMessage;
public final List<MyItem> items;
...
}
and then organize the fail and success messages in a
public class SuccesResponseObject extends ResponseObject {...}
and
public class FailResponseObject extends ResponseObject {...}
with the corresponding constructors. The properties will be situated in the superclass.
When using the classes, you should refer to them of being of the class ResponseObject
.
Upvotes: 2