2011-09-23 10 views
39

Sto sviluppando un'interfaccia RESTful che viene utilizzata per fornire dati JSON per un'applicazione JavaScript.Associazione JSON a oggetti di dominio Grails nidificati

Sul lato server utilizzo Grails 1.3.7 e utilizzo Oggetti Dominio GORM per la persistenza. Ho implementato una consuetudine JSON Marshaller per sostenere smistamento dominio nidificato oggetti

Qui ci sono oggetti di dominio di esempio:

class SampleDomain { 
    static mapping = { nest2 cascade: 'all' } 
    String someString 
    SampleDomainNested nest2 
} 

e

class SampleDomainNested { 
    String someField 
} 

La risorsa SampleDomain è pubblicato sotto l'URL/RS/campione/so/rs/sample/1 punta all'oggetto SampleDomain con ID 1

Quando eseguo il rendering della risorsa utilizzando il mio custom json marshaller (GET su/rs/sample/1), ottengo i seguenti dati:

che è esattamente quello che voglio.

Ora arriva il problema: provo a inviare gli stessi dati alla risorsa/rs/sample/1 via PUT.

Per collegare i dati JSON all'oggetto dominio, il controller che gestisce la richiesta chiama def domain = SampleDomain.get(id) e domain.properties = data dove i dati sono l'oggetto non protetto.

L'associazione per il campo "someString" funziona correttamente, ma l'oggetto nidificato non viene popolato utilizzando i dati nidificati, pertanto viene visualizzato un errore indicante che la proprietà "nest2" è nullo, il che non è consentito.

Ho già provato a implementare un numero personalizzato PropertyEditorSupport e un StructuredPropertyEditor e registrare l'editor per la classe.

Stranamente, l'editor viene chiamato solo quando fornisco valori non annidati. Così, quando mando il seguente al server tramite PUT (che non ha alcun senso;))

{ 
    "someString" : "somevalue1", 
    "nest2" : "test" 
} 

almeno l'editor di proprietà viene chiamato.

Ho esaminato il codice dello GrailsDataBinder. Ho scoperto che l'impostazione delle proprietà di un'associazione sembra funzionare specificando il percorso dell'associazione invece di fornire una mappa, in modo che il seguito a lavori così:

{ 
    "someString" : "somevalue1", 
    "nest2.somefield" : "someothervalue" 
} 

ma questo non mi aiuta quando ho don' t desidera implementare un codice JavaScript personalizzato per il serializzatore di oggetti JSON.

È possibile utilizzare l'associazione dati Grails utilizzando le mappe nidificate? O devo davvero implementarlo a mano per ogni classe di dominio?

Grazie mille,

Martin

+0

hai anche un unmarshaller JSON personalizzato? – fixitagain

+0

No, non ho un jab unmarshaller personalizzato. Analizzo la richiesta utilizzando request.JSON. Quello che vorrei è un editor di proprietà che supporta sia la creazione di un oggetto dominio da una mappa, sia il caricamento/mappatura di un oggetto dominio per ID. – frow

+1

Hai provato questo plugin: http://www.grails.org/plugin/json-rest-api –

risposta

1

Si richiede di fornire teh nome della classe:

{ class:"SampleDomain", someString: "abc", 
nest2: { class: "SampleDomainNested", someField:"def" } 
} 

lo so, richiede un input diverso che l'uscita che produce.

Come ho già detto nel commento precedente, potrebbe essere meglio usare la libreria gson.

1

Non sai perché hai scritto il tuo json marshaller, con xstream in giro.

Vedi http://x-stream.github.io/json-tutorial.html

Siamo stati molto soddisfatti xstream per il nostro back-end dei servizi (Grails based) e in questo modo è possibile rendere marshall in formato XML o JSON, o ignorare il marshalling predefinito per un oggetto specifico, se ti piace .

Jettison sembra produrre un JSON più compatto, meno umano, leggibile, e si può incappare in alcuni problemi di collisione della libreria, ma il renderer di flusso json interno predefinito è accettabile.

Se avete intenzione di pubblicare il servizio al pubblico, si vuole prendere il tempo per tornare adeguate risposte di protocollo HTTP per gli errori, ecc ... ($ .02)

7

Dal momento che questa domanda ha ottenuto diversi upvoted volte vorrei condividere ciò che ho fatto alla fine:

Poiché avevo altri requisiti da implementare come sicurezza, ecc. Ho implementato un livello di servizio che nasconde gli oggetti del dominio dai controller. Ho introdotto un "livello DTO dinamico" che traduce gli oggetti del dominio in Groovy Maps che possono essere serializzati facilmente utilizzando i serializzatori standard e che implementa manualmente gli aggiornamenti. Tutte le soluzioni basate su semi-automatico/meta-programmazione/schema di comando/... che ho provato ad implementare hanno fallito a un certo punto, per lo più con strani errori GORM o un sacco di codice di configurazione (e molta frustrazione). I metodi di aggiornamento e serializzazione per le DTO sono abbastanza semplici e potrebbero essere implementati molto rapidamente. Non introduce molto codice duplicato, poiché è necessario specificare in che modo gli oggetti del dominio vengono serializzati in ogni caso se non si desidera pubblicare la struttura dell'oggetto del dominio interno. Forse non è la soluzione più elegante ma è stata l'unica soluzione che ha funzionato davvero per me. Inoltre, consente di implementare aggiornamenti batch poiché la logica di aggiornamento non è più connessa alle richieste HTTP.

Tuttavia, devo dire che non penso che graal sia lo stack tecnologico appropriato più adatto per questo tipo di applicazione, dal momento che rende l'applicazione molto pesante e inflessbile. La mia esperienza è che una volta che si inizia a fare cose che non sono supportate dal framework di default, inizia a diventare disordinato. Inoltre, non mi piace il fatto che il livello "repository" in Grails esista essenzialmente solo come parte degli oggetti del dominio che hanno introdotto molti problemi e portato a diversi "servizi proxy" che emulano un livello di repository. Se inizi a creare un'applicazione utilizzando un'interfaccia json rest, ti suggerirei di optare per una tecnologia molto leggera come node.js o, se vuoi/dovermi attenere a uno stack basato su java, usa framework spring standard + primavera mvc + dati di primavera con uno strato dto bello e pulito (questo è ciò a cui sono migrato e funziona come un incantesimo). Non devi scrivere molto codice boilerplate e hai completamente il controllo di ciò che sta realmente accadendo. Inoltre, si ottiene una forte digitazione che aumenta la produttività degli sviluppatori e la manutenibilità e che legittima le LOC aggiuntive. E naturalmente una forte tipizzazione significa strumenti potenti!

Ho iniziato a scrivere un post di blog che descriveva l'architettura che mi è venuta in mente (con un progetto di esempio, ovviamente), tuttavia non ho molto tempo per terminarlo. Quando è fatto, vi collegherò qui per riferimento.

Spero che questo possa servire da ispirazione per le persone che hanno problemi simili.

Cheers!

+0

Grazie per questa intuizione, trovo molto utile. Ho iniziato a costruire un progetto con Grails di recente, e sto arrivando alle stesse conclusioni che hai fatto. Ho scelto Grails per capire i compromessi, molte chicche e cattivi. Ma questa limitazione su un oggetto complesso di smistamento è stata una grande sorpresa per me. Ora, ho un secondo pensiero, tornando a Spring MVC + Spring Data. L'unica cosa che mi mancherà è GSP. Sto trovando l'SPG, in particolare il sitemesh, molto potente. Conosci una tecnologia che può essere utilizzata con Spring MVC che è buono come GSP? –

+0

Dai un'occhiata a Thymeleaf. Ha un obiettivo molto simile a quello di GSP. –