2015-12-05 3 views
18

Ich bin mit Federdaten (MongoDB) und ich habe mein Repository konsumieren:Wie Seite <Entity> Antwort mit Spring RestTemplate

Dann habe ich einen Controller:

@RequestMapping(method = RequestMethod.GET) 
public ResponseEntity<Page<StoryResponse>> getStories(Pageable pageable) { 
    Page<StoryResponse> stories = storiesRepository.findAll(pageable).map(StoryResponseMapper::toStoryResponse); 
    return ResponseEntity.ok(stories); 
} 

Alles funktioniert gut, aber ich kann meinen Endpunkt nicht mit der RestTemplate getForEntity-Methode konsumieren:

Welche Klasse soll ich bereitstellen, um meine Seite von Entitäten erfolgreich zu deserialisieren?

Antwort

23
new TypeReference<Page<StoryResponse>>() {} 

Das Problem mit dieser Aussage ist, dass Jackson nicht eine abstrakte Art instanziiert. Sie sollten Jackson die Informationen geben, wie Sie Page mit einem konkreten Typ instanziieren können. Aber seine konkreten Typ, PageImpl, hat keinen Default-Konstruktor oder irgendwelche @JsonCreator s was das betrifft, so können Sie nicht den folgenden Code entweder:

new TypeReference<PageImpl<StoryResponse>>() {} 

Da Sie nicht die erforderlichen Informationen, um die Page hinzufügen Klasse, Es ist besser, eine benutzerdefinierte Implementierung für Page Schnittstelle zu erstellen, die einen Standardarrag-Konstruktor wie in diesem answer hat. Verwenden Sie dann die benutzerdefinierte Implementierung in Art Referenz, wie folgt vor:

new TypeReference<CustomPageImpl<StoryResponse>>() {} 

Hier wird die benutzerdefinierte Implementierung sind, aus verknüpften Frage kopiert:

public class CustomPageImpl<T> extends PageImpl<T> { 
    private static final long serialVersionUID = 1L; 
    private int number; 
    private int size; 
    private int totalPages; 
    private int numberOfElements; 
    private long totalElements; 
    private boolean previousPage; 
    private boolean firstPage; 
    private boolean nextPage; 
    private boolean lastPage; 
    private List<T> content; 
    private Sort sort; 

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

    @Override 
    public int getNumber() { 
     return number; 
    } 

    public void setNumber(int number) { 
     this.number = number; 
    } 

    @Override 
    public int getSize() { 
     return size; 
    } 

    public void setSize(int size) { 
     this.size = size; 
    } 

    @Override 
    public int getTotalPages() { 
     return totalPages; 
    } 

    public void setTotalPages(int totalPages) { 
     this.totalPages = totalPages; 
    } 

    @Override 
    public int getNumberOfElements() { 
     return numberOfElements; 
    } 

    public void setNumberOfElements(int numberOfElements) { 
     this.numberOfElements = numberOfElements; 
    } 

    @Override 
    public long getTotalElements() { 
     return totalElements; 
    } 

    public void setTotalElements(long totalElements) { 
     this.totalElements = totalElements; 
    } 

    public boolean isPreviousPage() { 
     return previousPage; 
    } 

    public void setPreviousPage(boolean previousPage) { 
     this.previousPage = previousPage; 
    } 

    public boolean isFirstPage() { 
     return firstPage; 
    } 

    public void setFirstPage(boolean firstPage) { 
     this.firstPage = firstPage; 
    } 

    public boolean isNextPage() { 
     return nextPage; 
    } 

    public void setNextPage(boolean nextPage) { 
     this.nextPage = nextPage; 
    } 

    public boolean isLastPage() { 
     return lastPage; 
    } 

    public void setLastPage(boolean lastPage) { 
     this.lastPage = lastPage; 
    } 

    @Override 
    public List<T> getContent() { 
     return content; 
    } 

    public void setContent(List<T> content) { 
     this.content = content; 
    } 

    @Override 
    public Sort getSort() { 
     return sort; 
    } 

    public void setSort(Sort sort) { 
     this.sort = sort; 
    } 

    public Page<T> pageImpl() { 
     return new PageImpl<>(getContent(), new PageRequest(getNumber(), 
       getSize(), getSort()), getTotalElements()); 
    } 
} 
+1

Jackson Fehler nicht vergessen '@JsonIgnoreProperties hinzufügen (ignoreUnknown = wahr) 'als eine Klassenannotation. Diese Eigenschaft wird dazu beitragen, die zusätzlichen Funktionen zu ignorieren, die eine benutzerdefinierte Zuordnung erfordern würden. –

-1

Sie können sich wahrscheinlich Austauschverfahren von restTemplate verwenden und den Körper von ihm erhalten ..

Überprüfen Sie die folgende Antwort https://stackoverflow.com/a/31947188/3800576. Dies könnte helfen Sie

+0

Ich habe versucht, mit ParameterizedTypeReference >(), aber bekam – bgalek

-5

Sie können versuchen, die @ResponseBody Anmerkung hinzuzufügen:

@RequestMapping(method = RequestMethod.GET) 
@ResponseBody 
public ResponseEntity<Page<StoryResponse>> getStories(@RequestBody Pageable pageable) { 
    Page<StoryResponse> stories = storiesRepository.findAll(pageable).map(StoryResponseMapper::toStoryResponse); 
    return ResponseEntity.ok(stories); 
} 
+0

Es hat nichts zu tun. Er will seinen Dienst über Resttemplate – Arnaud

+0

Dieses Problem ist auf der Verbraucherseite in Bezug auf die Deserialisierung der Seite JSON paypload Bezug nennen. Die Antwort scheint irrelevant. – chenrui

4

Ich weiß, dass dieser Thread ein wenig alt ist, aber hoffentlich wird jemand davon profitieren.

@Ali Dehghanis Antwort ist gut, außer dass es wieder implementiert, was PageImpl<T> bereits getan hat. Ich hielt dies für ziemlich überflüssig. Ich fand eine bessere Lösung durch Erstellen einer Klasse, die PageImpl<T> und gibt einen @JsonCreator Konstruktor erweitert:

import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.annotation.JsonProperty; 
import com.company.model.HelperModel; 
import org.springframework.data.domain.PageImpl; 
import org.springframework.data.domain.PageRequest; 

import java.util.List; 

public class HelperPage extends PageImpl<HelperModel> { 

    @JsonCreator 
    // Note: I don't need a sort, so I'm not including one here. 
    // It shouldn't be too hard to add it in tho. 
    public HelperPage(@JsonProperty("content") List<HelperModel> content, 
         @JsonProperty("number") int number, 
         @JsonProperty("size") int size, 
         @JsonProperty("totalElements") Long totalElements) { 
     super(content, new PageRequest(number, size), totalElements); 
    } 
} 

Dann:

HelperPage page = restTemplate.getForObject(url, HelperPage.class); 

Dies ist die gleiche wie die Schaffung eines CustomPageImpl<T> Klasse, sondern ermöglicht es uns, die Vorteile zu nehmen von der ganze Code, der bereits in PageImpl<T> ist.

+0

Ich bekomme diese Ausnahme, wenn ich versuchte, Ihren Ansatz zu verwenden: 'org.springframework.http.converter.HttpMessageConversionException: Typdefinition Fehler: [einfache Art, Klasse org.springframework.data.domain.Pageable]; verschachtelte Ausnahme ist com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Kann nicht Instanz org.springframework.data.domain.Pageable konstruieren (keine Creators, wie Standard-Konstrukt, existieren): abstrakte Typen müssen entweder auf konkrete Typen abgebildet werden , verfügen über benutzerdefinierte Deserializer oder enthalten zusätzliche Typ Informationen verstößt – Sriram

+0

@Sriram haben Sie überprüfen, dass 1. die 'HelperPage' Konstruktor der' @ JsonCreator' Anmerkung hat? 2. Sie erhalten eine 'HelpPage' von Ihrem RestTemplate? – Isammoc

+1

ist dies eine bessere Lösung als die akzeptierte Antwort. Hinzufügen von '@JsonIgnoreProperties (ignoreUnknown = true)' 'nach @JsonCreator verhindert auch Probleme deserialising, wenn es unbekannte Eigenschaften – robjwilkins

4

Als "Pathfinder" erwähnt können Sie exchange Methode von RestTemplate verwenden. Anstatt jedoch ParameterizedTypeReference<Page<StoryResponse>>() zu übergeben, sollten Sie ParameterizedTypeReference<PagedResources<StoryResponse>>() passieren. Wenn Sie die Antwort erhalten, können Sie den Inhalt abrufen - Collection<StoryResponse>.

Der Code sollte wie folgt aussehen:

ResponseEntity<PagedResources<StoryResponse>> response = restTemplate.exchange(getLocalhost("/story"), 
     HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<StoryResponse>>() {}); 
PagedResources<StoryResponse> storiesResources = response.getBody(); 
Collection<StoryResponse> stories = storiesResources.getContent(); 

Neben den Inhalt storiesResources zu Seite Metadaten und Links enthält.

Eine Schritt-für-Schritt-Anleitung finden Sie hier: https://stackoverflow.com/a/46847429/8805916