I struggle using Spring-boot for creating a REST client for the Synology FileStation API. Indeed, the API uses the same attribute to store different kind of objects. The attribute used is data and it can store either the sid or the content of a search result like file shares.
For search result :
{
"data": {
"offset": 0,
"shares": [
{
"isdir": true,
"name": "config",
"path": "/config"
},
...
],
"total": 19
},
"success": true
}
For login result :
{
"data": {
"sid": "blablablabla",
},
"success": true
}
For bad login error :
{
"error": {
"code": 400,
},
"success": false
}
I tried to design model for each type of response, but I cannot find a proper way to use Jackson to deserialize it.
To make it simple, the class that is used for receiving the response is Reponse, in the response there is a success field, and two other fields: Data and Error. Depending on the response, the Data to be instanciated is either a LoginResponse or ListShares object.
Here is the code of my classes :
@JsonIgnoreProperties(ignoreUnknown = true)
public class Response {
@JsonProperty("success")
private boolean success;
@JsonProperty(value = "data")
private Data data;
@JsonProperty(value = "error")
private Error error;
...
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class Error {
private int code;
private Collection<ErrorInfo> errors;
public Error( int code, Collection<ErrorInfo> errors) {
super();
this.code = code;
this.errors = errors;
}
...
}
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = LoginResponse.class),
@JsonSubTypes.Type(value = ListShares.class),
})
public abstract class Data {
}
@JsonTypeName("LoginResponse")
public class LoginResponse extends Data {
@JsonProperty("sid")
private String sid;
public LoginResponse() {
super();
}
...
}
@JsonTypeName("ListShares")
public class ListShares extends Data {
@JsonProperty("offset")
private int offset;
@JsonProperty("total")
private int total;
@JsonProperty("shares")
private Set<Share> shares;
public ListShares() {
super();
}
public ListShares(int offset, int total, Set<Share> shares) {
super();
this.offset = offset;
this.total = total;
this.shares = shares;
}
I get this exception :
Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class com.heavyrage.syno.apis.genericresponses.Response]: missing type id property 'data'
at [Source: (PushbackInputStream); line: 1, column: 38]
at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:1794) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1323) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:303) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:166) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:107) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3487) ~[jackson-databind-2.11.1.jar:2.11.1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:273) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
... 17 common frames omitted
Does someone know if it is possible to instanciate the Data object correctly (instanciate LoginResponse or ListShare) to populate the "data" property of the Response object ?