2

Similar to this question, I want to exchange information between two microservices. However the difference is, that my generics is an abstract class and by this I'm having trouble.

My class looks like that:

public <T extends Account> Page<T> getAllAccounts() {   // not working
    ParameterizedTypeReference<Page<T>> responseType = new ParameterizedTypeReference<Page<T>>() { };
    ResponseEntity<Page<T>> result = restTemplate.exchange("http://localhost:8080/api/v1/accounts/", HttpMethod.GET, null, responseType);

    Page<T> accounts = result.getBody();
    
    return accounts;
}

The function behind the API-call has the return type public <T extends Account> Page<T> getAccounts...) {..}. T can be everything that extends Account, because there are several "Accounts" possible.

The given method also works for non-abstract classes (e.g. Page<CustomerAccount>), however with abstract classes it doesn't.

If I try to call the function, I get the following error message:

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Dec 18 14:55:33 CET 2020
There was an unexpected error (type=Internal Server Error, status=500).
Type definition error: [simple type, class org.springframework.data.domain.Page]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Page` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: (PushbackInputStream); line: 1, column: 1]
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.data.domain.Page]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Page` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: (PushbackInputStream); line: 1, column: 1]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:282)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:243)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:105)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1034)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1017)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:777)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:710)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:630)
    at de.rwth.swc.lab.ws2021.daifu.businesslogic.services.AccountService.getAllAccounts(AccountService.java:50)
    at de.rwth.swc.lab.ws2021.daifu.businesslogic.api.AccountController.getAllAccounts(AccountController.java:47)
... (rest shortend for better readability)

Question

How can I communicate from Port 8081 with the MS running on port 8080 with "abstract generics" (I think you call them different, but idk atm :D)

Niklas
  • 109
  • 1
  • 10
  • 1
    You're trying to instantiate new instances through this method, it's better to use generics in this case for already instantiated objects. That said, you should probably ditch the generics here, and utilize the methods available to you through `Account`/etc. You could also look into factory, memento, and decorator design patterns. Lastly, note this line in the error in particular: `abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information` – Rogue Dec 18 '20 at 14:14
  • What do you mean by "ditch teh generics"? The return of the request should contain all possible classes, which extend `account`. Therefore, I can't just leave you out. Besides, the other API service is predefined and must not be changed. I would prefer to be able to fix the error - could cou tell me how? :) – Niklas Dec 18 '20 at 16:10
  • You could just return a `Page` (which is what you want), and then you would provide a deserializer to turn the stored data into an `Account` object. Hence, the factory pattern. – Rogue Dec 18 '20 at 16:23
  • But then I would lose information from classes which extend Account e.g. by another String customerName or something, wouldn't I? – Niklas Dec 18 '20 at 16:25
  • Just because you refer to something as its abstract type, doesn't change the underlying object. For an adjacent example, in `List ex = new ArrayList<>();`, `ex` would still be an `ArrayList` (and could be casted to such or checked via `instanceof`), but is referred to as a `List`. Furthermore, `List` provides the methods needed to use it appropriately. – Rogue Dec 18 '20 at 16:27
  • Ahh okay, that makes sense. Thanks! However, if I change the return type to `Page` and adjust the types in the getAllAccounts-function, I still get the same error :/ – Niklas Dec 18 '20 at 16:32
  • Correct, and for the same reason: you need to specify something (a deserializer) that turns the saved back-end data into objects. In your case, `Account` objects: you'd create the object which was relevant and return it accordingly. The program still doesn't know how to turn your data into those objects. – Rogue Dec 18 '20 at 16:36
  • Mhh, do you have a link with an example for creating such a deserializer? I've never heard of it before... I'm not sure how to implement a deserializer and how to use it in my code :/ – Niklas Dec 18 '20 at 16:39
  • It really depends a lot on what you're doing in your actual code, enough that I'll say it'll be easier for you to google around things like "spring boot deserializer" and parsing through some examples. From there look up the javadocs of the classes used in the examples – Rogue Dec 18 '20 at 16:41
  • Sadly also after 2 hours of googling I have absolutly no Idea how I have to do this... I tried several things and also switched to webCliend (because I found out restTemplate is deprecated) and still the same error and I have no clue how to use a serializer / build a custom one... – Niklas Dec 18 '20 at 19:03

0 Answers0