将JSON绑定到嵌套的Grails域对象
我正在开发一个用于为JavaScript应用程序提供JSON数据的RESTful接口。
在服务器端,我使用Grails 1.3.7并使用GORM域对象进行持久化。 我实现了一个自定义的JSON Marshaller来支持编组嵌套的域对象
以下是示例域对象:
class SampleDomain { static mapping = { nest2 cascade: 'all' } String someString SampleDomainNested nest2 }
和
class SampleDomainNested { String someField }
SampleDomain资源在URL / rs / sample / so / rs / sample / 1下发布到ID为1的SampleDomain对象
当我使用自定义的json编组器(GET / rs / sample / 1)呈现资源时,我得到以下数据:
{ "someString" : "somevalue1", "nest2" : { "someField" : "someothervalue" } }
这正是我想要的。
现在出现这个问题:我尝试通过PUT将相同的数据发送到资源/ rs / sample / 1。
为了将json数据绑定到域对象,处理请求的控制器调用def domain = SampleDomain.get(id)
和domain.properties = data
,其中data是解组对象。
“someString”字段的绑定工作得很好,但嵌套对象没有使用嵌套数据填充,所以我得到一个错误,即属性“nest2”为空,这是不允许的。
我已经尝试实现一个自定义的PropertyEditorSupport
以及一个StructuredPropertyEditor
并注册该类的编辑器。
奇怪的是,只有当我提供非嵌套的值时才会调用编辑器。 所以当我通过PUT发送以下内容到服务器(这没有任何意义;))
{ "someString" : "somevalue1", "nest2" : "test" }
至less属性编辑器被调用。
我看了一下GrailsDataBinder
的代码。 我发现一个关联的设置属性似乎是通过指定关联的path而不是提供一个地图,所以下面的工作也是如此:
{ "someString" : "somevalue1", "nest2.somefield" : "someothervalue" }
但是这并不能帮助我,因为我不想实现一个自定义JavaScript到JSON对象序列化器。
是否有可能使用嵌套地图使用Grails数据绑定? 还是我真的很想为每个领域的类实现呢?
非常感谢,
马丁
由于这个问题得到了好几次,我想分享我最后做了什么:
由于我有更多的要求像安全等实施,我实现了一个服务层,从控制器隐藏域对象。 我介绍了一个“dynamicDTO层”,它将域对象转换为Groovy Maps,可以使用标准序列化器轻松地序列化并手动实现更新。 我尝试实现的所有基于半自动/元编程/命令模式/ …的解决scheme在某些时候失败了,主要是导致了奇怪的GORM错误或者很多configuration代码(以及很多挫折)。 DTO的更新和序列化方法非常简单,可以很快实现。 它不会引入大量的重复代码,因为如果不想发布内部域对象结构,必须指定域对象的序列化方式。 也许这不是最优雅的解决scheme,但它是真正为我工作的唯一解决scheme。 它也允许我实现批量更新,因为更新逻辑没有再连接到http请求。
但是我必须说,我不认为Grails是最适合这种应用的合适的技术栈,因为它使得你的应用程序非常笨重和不可靠。 我的经验是,一旦你开始做缺乏框架支持的事情,它开始变得凌乱。 此外,我不喜欢grails中的“存储库”层只是作为域对象的一部分存在,导致了很多问题,并导致了几个模拟存储库层的“代理服务”。 如果你开始使用json rest接口来构build一个应用程序,那么我会build议你select一个像node.js这样的非常轻量级的技术,或者如果你想要/必须坚持一个基于java的堆栈,可以使用标准的spring framework +springmvc +spring的数据与一个漂亮干净的dto层(这是我已经迁移到,它的作品像一个魅力)。 您不必编写大量的样板代码,并且完全掌控实际发生的事情。 此外,您可以获得强大的打字能力,从而提高了开发人员的生产力以及可维护性,并增加了其他LOC的合法性。 当然,强大的打字意味着强大的工具!
我开始写一篇博客文章,描述我提出的架构(当然还有一个示例项目),但现在我没有太多时间来完成它。 完成后我会链接到这里以供参考。
希望这可以作为遇到类似问题的人的灵感。
干杯!
它要求你提供类名:
{ class:"SampleDomain", someString: "abc", nest2: { class: "SampleDomainNested", someField:"def" } }
我知道,它需要不同的input,它产生的输出。
正如我在前面的评论中提到的那样,使用gson库可能会更好。
不知道为什么你用xstream编写自己的json编组器。
请参阅http://x-stream.github.io/json-tutorial.html
对于我们的后端(基于grails的)服务,我们对xstream非常满意,这样,您可以使用xml或json渲染marshall,或者根据需要覆盖特定对象的默认编组。
Jettison似乎产生一个更紧凑的人类可读的JSON,你可以碰到一些库碰撞的东西,但默认的内部jsonstream渲染器是体面的。
如果你打算把这个服务发布给公众,你将需要花时间来返回适当的HTTP协议响应错误等等($ .02)