在Grails中将Marshal / unmarshal域实例转换为JSON

时间:2014-10-23 16:44:56

标签: json grails gorm marshalling unmarshalling

我试图将域(例如OrgUnit)实例作为JSON编组并解组为数据库字段,如下所示:

class OrgUnit{
  String name
  OrgUnit parent
  static hasMany = [children:orgUnit]
}

class History{
  String data
}

class OrgUnitService{

  History marshal(OrgUnit orgUnit){
      return new History([
          data : (orgUnit.properties as JSON).toString()
          ]).save()

  }

  OrgUnit unmarshal(History history){
     return OrgUnit.newInstance( JSON.parse(history.data))
  }
}

它适用于像name这样的简单字段,但是像子节点这样的字段在unmarshaled对象中是空的。

history.data字段包含以下子信息:

{"name":"b","children":[{"class":"demo.OrgUnit","id":3,"children":null,"name":"c"}]}

我使用的是Grails 2.2.4。 有什么建议!?

更新 我在Grails 2.4.3上测试过它。它按预期工作。 history.data字段的内容在两个Grails版本中都相同。问题在于解组部分。

1 个答案:

答案 0 :(得分:0)

关键部分是 properties map创建域实例。它用于控制器中的默认保存操作。它可能是控制器中的安全问题,但我将其从范围中删除。

在Grails版本2.2.4中,它不会将引用与实例绑定。 解决方法是,手动执行此操作:

class HistoryService {

    def grailsApplication

    History marshal(OrgUnit orgUnit) {
        return new History([
            data: (orgUnit.properties as JSON).toString()
        ]).save(failOnError: true)

    }

    OrgUnit unmarshal(History history) {
        def data = JSON.parse(history.data)
        OrgUnit instance = OrgUnit.newInstance(data)
        def domainClass = grailsApplication.getDomainClass(OrgUnit.class.name)

        domainClass.persistentProperties.each{p->
            if (p.oneToMany || p.manyToMany){
                def refDataList = data."$p.name"
                refDataList.each{refData->
                    instance."$p.name" << getDomainClass(refData.class).read(refData.id as Long) 
                }
            }else if (p.manyToOne || p.oneToOne){
                def refData = data."$p.name"
                if(refData && refData.class && refData.id){ // if reference field has value null
                    instance."$p.name" = getDomainClass(refData.class).read(refData.id as Long)
                }
            }
        }

        return instance
    }

    private def getDomainClass(String domainName){
        return grailsApplication.classLoader.loadClass(domainName)
    }
}