jasminb / jsonapi-converter

JSONAPI-Converter is a Java/Android library that provides support for working with JSONAPI spec
Apache License 2.0
272 stars 81 forks source link

Pagination is not supported with decode fein in Java Spring boot #268

Open SoheibOuad opened 1 week ago

SoheibOuad commented 1 week ago

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);
}

}`