Search code examples
javaspringspring-bootwebclientpageable

Missing Attribute 'type' in Spring WebClient Response for Microservice Communication


I want to use WebClient to retrieve a page from another microservice. When I directly request the microservice using Postman, the response includes the type attribute among other fields in the content section. However, when I make the request via WebClient, the type attribute (and some other fields) disappear from the content section. The content is a list of objects of the abstract class Account. which uses JsonSubTypes for polymorphic deserialization.

Can someone help me identify the mistake and understand why the "type" attribute disappears when using WebClient to call the microservice?

Here are the sample responses for comparison:

Responses

Response from http://localhost:8080/api/v1/accounts

{
    "content": [
        {
            "type": "savingsBook",
            "id": 108,
            "accountNumber": 99781944,
            ...
        }
    ], "pageable": {
        ...
    }, "totalPages": ...
    ...
}
    

Response from http://localhost:8081/accounts

{
    "content": [
        {
            "id": 108,
            "accountNumber": 99781944,
            ...
        }
    ], "pageable": {
        ...
    }, "totalPages": ...
    ...
}

Code-Snippets:

8080's account controller

@RequestMapping(method = RequestMethod.GET, produces = "application/json")
public <T extends Account> Page<T> getAccounts(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "pageSize", required = false) Integer pageSize, @RequestParam(value = "sortBy", required = false) String sortBy) {
    if (page == null) {
        page = 0;
    }
    if (pageSize == null) {
        pageSize = 10;
    }
    if (sortBy == null) {
        Page<T> p = accountService.getAccounts(page, pageSize);
        return new PageImpl<T>(p.getContent(), p.getPageable(), p.getTotalElements()) {};

    } else {
        Sort sort = Sort.by(sortBy);
        Page<T> p = accountService.getAccounts(page, pageSize, sort);
        return new PageImpl<T>(p.getContent(), p.getPageable(), p.getTotalElements()) {};
    }
}

8081 Account Controler

@GetMapping
public  <T extends Account> Page<T> getAllAccounts(@RequestParam(value = "page", required = false) Integer page, 
                                                   @RequestParam(value = "pageSize", required = false) Integer pageSize,
                                                   @RequestParam(value = "sortBy", required = false) String sortBy) {   
     if (page == null) {
         page = 0;
     }
     if (pageSize == null) {
         pageSize = 10;
     }
     if (sortBy == null) {
         return accountService.getAllAccounts(page, pageSize);
     } else {
         return accountService.getAllAccounts(page, pageSize, sortBy);
     }
}

8081 AccountService

public <T extends Account> Page<T> getAllAccounts(Integer pageNumber, Integer pageSize) {
    ParameterizedTypeReference<CustomPageImpl<T>> typeReference = new ParameterizedTypeReference<CustomPageImpl<T>>(){};
    System.out.println("Anfrage an: " + addr + "/accounts/");
    System.out.println(client.get().uri("/accounts/").retrieve().bodyToMono(typeReference).block().getContent());
    Page<T> prodData = (CustomPageImpl<T>)(client.get().uri("/accounts/").retrieve().bodyToMono(typeReference).block());
    return prodData;
}

CustomPageImpl (got it from another StackOverflow-Post)

public class CustomPageImpl<T> extends PageImpl<T> {
    private static final long serialVersionUID = 1L;

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public CustomPageImpl(@JsonProperty("content") List<T> content,
            @JsonProperty("number") int number,
            @JsonProperty("size") int size,
            @JsonProperty("totalElements") Long totalElements,
            @JsonProperty("pageable") JsonNode pageable,
            @JsonProperty("last") boolean last,
            @JsonProperty("totalPages") int totalPages,
            @JsonProperty("sort") JsonNode sort,
            @JsonProperty("first") boolean first,
            @JsonProperty("numberOfElements") int numberOfElements){
        super(content, PageRequest.of(number, size) , totalElements);
    }
    public CustomPageImpl(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public CustomPageImpl(List<T> content) {
        super(content);
    }

    public CustomPageImpl() {
        super(new ArrayList<>());
    }
}
    

Solution

  • I found an answer to this question on my own.

    The problem is the fact, that Account is abstract and has json subtypes. By replacing public class CustomPageImpl<T> extends PageImpl<T> by public class CustomPageImpl<T extends Account> extends PageImpl<T> I was able to solve this issue. Now I receive the type as planned.