2011-09-23 21 views
39

Estoy desarrollando una interfaz RESTful que se utiliza para proporcionar datos JSON para una aplicación JavaScript.Enlace JSON a objetos de dominio Grails anidados

En el lado del servidor, uso Grails 1.3.7 y uso objetos de dominio GORM para la persistencia. He implementado una costumbre JSON Marshaller para apoyar el guiado de la de dominios anidados objetos

Éstos son los objetos de dominio de muestra:

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

y

class SampleDomainNested { 
    String someField 
} 

El recurso SampleDomain se publica bajo la URL/rs/muestra/so/rs/sample/1 puntos al objeto SampleDomain con ID 1

Cuando renderizo el recurso utilizando mi masonhaller json personalizado (GET on/rs/sample/1), obtengo los siguientes datos:

{ 
    "someString" : "somevalue1", 
    "nest2" : { 
     "someField" : "someothervalue" 
    } 
} 

que es exactamente lo que quiero.

Ahora viene el problema: trato de enviar los mismos datos al recurso/rs/sample/1 a través de PUT.

Para enlazar los datos json con el objeto de dominio, el controlador que maneja la solicitud llama a def domain = SampleDomain.get(id) y domain.properties = data donde los datos son el objeto no agrupado.

El enlace del campo "someString" funciona correctamente, pero el objeto anidado no se completa con los datos anidados, por lo que aparece un error que indica que la propiedad "nest2" es nula, lo que no está permitido.

Ya he intentado implementar un PropertyEditorSupport personalizado así como un StructuredPropertyEditor y registrar el editor para la clase.

Extrañamente, el editor solo recibe una llamada cuando proporciono valores no anidados. Así que cuando envío el siguiente al servidor a través PUT (lo que no tiene ningún sentido;))

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

al menos, el editor de la propiedad es llamada.

Miré el código de GrailsDataBinder. Descubrí que la configuración de propiedades de una asociación parece funcionar especificando la ruta de la asociación en lugar de proporcionar un mapa, por lo que el siguiente también funciona:

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

pero esto no me ayuda desde que don' Quiero implementar un JavaScript personalizado para el serializador de objetos JSON.

¿Es posible utilizar el enlace de datos Grails usando mapas anidados? ¿O realmente me esfuerzo por implementar eso a mano para cada clase de dominio?

Muchas gracias,

Martin

+0

¿Tiene también un jason unmarshaller personalizado? – fixitagain

+0

No, no tengo un unmarshaller json personalizado. Analizo la solicitud utilizando request.JSON. Lo que me gustaría es un editor de propiedades que admita tanto la creación de un objeto de dominio desde un Mapa como la carga/mapeo de un objeto de dominio por ID. – frow

+1

¿Has probado este plugin ?: http://www.grails.org/plugin/json-rest-api –

Respuesta

1

Se requiere que proporcione teh nombre de la clase:

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

que sé, se requiere de entrada diferente que la salida que produce.

Como mencioné en el comentario anterior, es mejor que utilices la biblioteca gson.

1

No estoy seguro de por qué escribió su propio json marshaller, con xstream alrededor.

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

Hemos sido muy feliz con xstream por nuestra parte final (basados ​​Grails) los servicios y de esta manera se puede hacer Marshall en XML o JSON o anular el cálculo de referencias predeterminado para un objeto específico si te gusta .

Jettison parece producir un JSON legible menos humano y más compacto, y puede encontrarse con algunas cosas de colisión de la biblioteca, pero el renderizador interno de json stream es decente.

Si se va a publicar el servicio al público, tendrá que tomar el tiempo para devolver respuestas protocolo HTTP apropiados para los errores, etc ... ($ .02)

7

Dado que esta cuestión quedó upvoted varios veces me gustaría compartir lo que hice al final:

Como tenía más requisitos para implementar como seguridad, etc. Implementé una capa de servicio que oculta los objetos de dominio de los controladores. Introduje una "capa dinámica de DTO" que traduce Objetos de Dominio a Groovy Maps que se pueden serializar fácilmente utilizando los serializadores estándar y que implementa las actualizaciones de forma manual. Todas las soluciones basadas en semiautomática/metaprogramación/patrón de comando/... que traté de implementar fallaron en algún momento, principalmente como resultado de extraños errores GORM o una gran cantidad de código de configuración (y mucha frustración). Los métodos de actualización y serialización para los DTO son bastante sencillos y podrían implementarse muy rápidamente. Tampoco introduce una gran cantidad de código duplicado, ya que debe especificar cómo se serializan los objetos de su dominio de todos modos si no desea publicar su estructura interna de objeto de dominio. Tal vez no es la solución más elegante, pero fue la única solución que realmente funcionó para mí. También me permite implementar actualizaciones por lotes ya que la lógica de actualización ya no está conectada a las solicitudes http.

Sin embargo, debo decir que no creo que Grails sea la pila tecnológica adecuada más adecuada para este tipo de aplicación, ya que hace que su aplicación sea muy pesada e inflexible. Mi experiencia es que una vez que comienzas a hacer cosas que no son compatibles con el framework por defecto, comienza a complicarse. Además, no me gusta el hecho de que la capa "repositorio" en griales esencialmente solo existe como parte de los objetos de dominio que introdujeron muchos problemas y dieron como resultado varios "servicios proxy" que emulaban una capa de repositorio. Si comienzas a construir una aplicación usando una interfaz json rest, te sugiero elegir una tecnología muy liviana como node.js o, si quieres/debes apegarte a una pila basada en Java, utiliza el marco de resorte estándar + spring mvc + spring data con una capa dto agradable y limpia (esto es a lo que he migrado y funciona como un amuleto). No tiene que escribir mucho código repetitivo y tiene el control total de lo que realmente está sucediendo. Además, obtiene un tipado fuerte que aumenta la productividad del desarrollador, así como la capacidad de mantenimiento, y que legitima los LOC adicionales. ¡Y por supuesto una tipificación fuerte significa herramientas fuertes!

Empecé a escribir una entrada de blog que describe la arquitectura que se me ocurrió (con un proyecto de ejemplo, por supuesto), pero ahora no tengo mucho tiempo para terminarla. Cuando esté listo, voy a vincularlo aquí como referencia.

Espero que esto sirva de inspiración para las personas que experimentan problemas similares.

¡Salud!

+0

Gracias por esta idea, me parece muy útil. Comencé a construir un proyecto con Grails recientemente, y estoy llegando a la misma conclusión que tú. Elijo a Grails comprendiendo las compensaciones, muchas cosas buenas y malas. Sin embargo, esta limitación para desarticular objetos complejos fue una gran sorpresa para mí. Ahora, lo estoy pensando, volviendo a Spring MVC + Spring Data. Lo único que voy a extrañar es GSP. Estoy encontrando el GSP, especialmente sitemesh, muy poderoso. ¿Conoces alguna tecnología que se pueda usar con Spring MVC que sea tan buena como GSP? –

+0

Eche un vistazo a Thymeleaf. Tiene un objetivo muy similar a GSP. –

Cuestiones relacionadas