Pagination is not supported with decode fein in Java Spring boot
I do this to retrieve the links information that is in the root of the json-api response to manage pagination
I get this error when I retrieve the result from jsonapi: feign.codec.DecodeException: Primary data must be either a single resource object, a single resource identifier object, or null
I have this response model from jsonapi.
{ "data": [ { "type": "node--demande_de_support", "id": "1", "attributes": { "title": "value1", "field_statut_de_la_demande": "value2", "changed": "value3" } } ], "links": { "next": { "href": "https://url/jsonapi/node/demande_de_support? include=field_objet_de_la_demande&page%5Boffset%5D=50&page%5Blimit%5D=50" }, "self": { "href": "https://url/jsonapi/node/demande_de_support?include=field_objet_de_la_demande" } } }
This is the model DTO that will be contain the converted
`@Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) public class DrupalSavRequestResponseDTO {
private List<DrupalSavRequestDTO> data;
@Links
private com.github.jasminb.jsonapi.Links links;
}`
and DrupalSavRequestDTO is :
`@Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) @Type("node--demande_de_support") public class DrupalSavRequestDTO extends JsonApiBaseModel {
@JsonProperty("title")
String title;
@JsonProperty("field_statut_de_la_demande")
String status;
@JsonProperty("changed")
String modificationDate;
}`
I'm using jsonapi-converter in my project java spring boot to decode and encode using this configuration :
`import feign.RequestInterceptor ; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; import com.github.jasminb.jsonapi.ResourceConverter;
import feign.codec.Decoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder;
@Slf4j public class JsonApiControllerConfiguration {
public JsonApiControllerConfiguration() {
}
@Bean
public Encoder feignEncoder() {
ResourceConverter resourceConverter = new ResourceConverter(Test.class);
return new JsonApiEncoder(resourceConverter);
}
@Bean
public Decoder feignDecoder() {
ResourceConverter resourceConverter = new ResourceConverter(Test.class);
return new JsonApiDecoder(resourceConverter);
}
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}`
And i have custom JsonApiDecoder :
`import java.io.IOException; import java.lang.reflect.Type; import java.util.Collection;
import com.github.jasminb.jsonapi.JSONAPIDocument; import com.github.jasminb.jsonapi.ResourceConverter;
import feign.Response; import feign.codec.Decoder; import java.lang.reflect.ParameterizedType; import lombok.extern.slf4j.Slf4j;
@Slf4j public class JsonApiDecoder implements Decoder {
private final ResourceConverter resourceConverter;
public JsonApiDecoder(ResourceConverter resourceConverter) {
this.resourceConverter = resourceConverter;
}
@Override
public Object decode(Response response, Type type) throws IOException {
if (response.body() == null) {
return null;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type actualType = parameterizedType.getActualTypeArguments()[0];
if (actualType instanceof Class<?>) {
Class<?> clazz = (Class<?>) actualType;
JSONAPIDocument<?> document;
if (Collection.class.isAssignableFrom((Class<?>) parameterizedType.getRawType())) {
document = resourceConverter.readDocumentCollection(response.body().asInputStream(),
clazz);
} else {
document = resourceConverter.readDocument(response.body().asInputStream(),
clazz);
}
return document.get();
}
}
if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>) type;
JSONAPIDocument<?> document = resourceConverter.readDocument(response.body().asInputStream(), clazz);
return document.get();
}
throw new IOException("Type not supported: " + type);
}
}`
@SoheibOuad thank you for reporting the issue, I will try to investigate next week. Cheers!
@SoheibOuad there must be something off in how you are deciding when to use readDocument and when to use readDocumentCollection as it works for in the following unit test:
@Test
public void testReportedIssue() throws IOException {
converter.registerType(CollectionDeserIssue.class);
String data = "{\"data\":[{\"type\":\"node--demande_de_support\",\"id\":\"1\",\"attributes\":{\"title\":\"value1\",\"field_statut_de_la_demande\":\"value2\",\"changed\":\"value3\"}}],\"links\":{\"next\":{\"href\":\"https://url/jsonapi/node/demande_de_support?include=field_objet_de_la_demande&page%5Boffset%5D=50&page%5Blimit%5D=50\"},\"self\":{\"href\":\"https://url/jsonapi/node/demande_de_support?include=field_objet_de_la_demande\"}}}";
JSONAPIDocument<List<CollectionDeserIssue>> deser = converter.readDocumentCollection(data.getBytes(StandardCharsets.UTF_8), CollectionDeserIssue.class);
System.out.println(deser.get().get(0).getTitle());
}
@Type("node--demande_de_support")
static class CollectionDeserIssue {
@Id
private String id;
@JsonProperty("title")
String title;
@JsonProperty("field_statut_de_la_demande")
String status;
@JsonProperty("changed")
String modificationDate;