Ich habe folgende Controller:Frühling generic REST-Controller: Parsen Anfrage Körper
@RestController
@RequestMapping(value = "/{entity}", produces = MediaType.APPLICATION_JSON_VALUE)
public class CrudController<T extends SomeSuperEntity> {
@RequestMapping(method = GET)
public Iterable<T> findAll(@PathVariable String entity) {
}
@RequestMapping(value = "{id}", method = GET)
public T findOne(@PathVariable String entity, @PathVariable String id) {
}
@RequestMapping(method = POST)
public void save(@PathVariable String entity, @RequestBody T body) {
}
}
SomeSuperEntity
Klasse wie folgt aussieht:
public abstract class SomeSuperEntity extends AbstractEntity {
// some logic
}
Und AbstractEntity
seine abstrakte Klasse mit einem Feld:
public abstract class AbstractEntity implements Comparable<AbstractEntity>, Serializable {
private Timestamp firstField;
private String secondField;
public Timestamp getFirstField() {
return firstField;
}
public void setFirstField(Timestamp firstField) {
this.firstField = firstField;
}
public String getSecondField() {
return secondField;
}
public void setSecondField(String secondField) {
this.secondField = secondField;
}
}
Alle Unterklassen von SomeSuperEntity
- einfache JavaBeans. Im Fall mit findAll()
und findOne(id)
Methoden - alles funktioniert gut. Ich erstelle Entität in Service-Schicht und es wird an den Client als JSON mit allen Feldern zurückgegeben, die in der Unterklasse und in AbstractEntity
deklariert sind.
Aber wenn ich versuchte Anfrage Körper in save(entity, body)
zu bekommen, ich habe Fehler folgende:
Could not read document: Can not construct instance of SomeSuperEntity, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
Wenn ich von SomeSuperEntity
abstrakt entfernen, alles funktioniert, aber ich wünsche Körper i nur jene Felder bekam, die deklariert in AbstractEntity
.
Und hier ist meine Frage, gibt es eine Problemumgehung für solche Probleme in meinem Fall? Wenn nicht, was würde sich durch die beste Lösung hier ohne Struktur ändern (subcontroller für jede Entität zu machen ist keine Option)? Ist retrieve body als einfacher Text eine gute Idee? Oder wäre es besser, dafür Map
zu verwenden?
Ich verwende Spring v4.2.1 und Jackson 2.6.3 als Konverter.
Es gibt ein paar Informationen über generische Controller, aber ich konnte nichts finden, was meinen Fall abdeckt. Also, bitte, navigieren Sie im Falle einer doppelten Frage.
Vielen Dank im Voraus.
UPD: Zur Zeit seiner Arbeits wie folgt: füge ich zusätzliche Kontrolle in meinem MessageConverter
hinzufügen und definieren @RequestBody
als String
Dann auf Dienstschicht definieren i, welche Entität empfangen (im Klar json) und wandeln es:
final EntityMetaData entityMetadata = getEntityMetadataByName(alias);
final T parsedEntity = getGlobalGson().fromJson(entity, entityMetadata.getEntityType());
Wo EntityMetaData
enum
mit definierten Beziehungen zw Ein Entitätsalias und eine Klasse. Alias kommt als @PathVariable
.
Spring erstellt ein einzelnes Objekt für den Typ "CrudController". Es gibt keine zusätzlichen Informationen, z. der Subtyp "SomeSuperEntity". Wo erwartest du Spring (und dann Jackson)? –
Im Grunde tun Sie nicht, was Sie mit 'CrudController' gemacht haben. Erstellen Sie eine dedizierte '@ Controller'-Klasse für jeden gewünschten Typ mit entsprechenden Zuordnungen. –
Das ist interessant. Warum? Was ist falsch bei der Bereitstellung eines allgemeinen "/ Tiere" - oder "/ Tiere/1" -Endpunkts, um alle Tiere oder Tiere mit ID = 1 zu erhalten, unabhängig davon, ob es sich um einen Hund oder eine Katze handelt? Sie schlagen vor, die Leute im Voraus wissen zu lassen, ob sie Hunde oder Katzen anfordern, oder? Wie '/ Tiere/Hunde/1'. Auch wenn Sie alle Tiere bekommen wollen, müssen Sie über alle Tierarten iterieren, indem Sie '/ animals/dogs','/animals/cats' usw. sammeln. Fragen Sie mich einfach, während ich versuche, ähnliche Fälle zu lösen der beste Weg. –