1

我想教我的域类自动将 JSON.parse(someJSON) 的结果转换为也是自定义域类的成员。

给定这些域类:

class Person {
    Long id
    String name

    static hasMany = [aliases: PersonAlias]
}

class PersonAlias {
    Person person
    Long id
    String name
}

这个 JSON 代表一个带有一些 PersonAliases 的人:

{
     "id":20044397,
     "name":"John Smith",
     "aliases":[{"id":13376,"name":"Johnny Smith"},{"id":13377,"name":"J. Smith"}]
}

我想保持控制器简单,例如:

class PersonController {
    def saveViaAjax = {
        def props = JSON.parse(params.JSON)
        Person p = Person.get(props.id)
        p.properties = props
        p.save(flush: true)
    }
}

但遗憾的是我收到了这个错误:

无法将类型“org.codehaus.groovy.grails.web.json.JSONArray”的属性值转换为属性“别名”所需的类型“java.util.Set”;嵌套异常是 java.lang.IllegalStateException:无法将类型 [org.codehaus.groovy.grails.web.json.JSONObject] 的值转换为属性“别名 [0]”所需的类型 [heavymeta.PersonAlias]:没有匹配的编辑器或找到转换策略

所以,我想教我的领域类如何将 JSON 数据自动转换为 PersonAlias 实例。我想避免在将控制器中的数据传递给域对象之前对其进行格式化。我如何实现这些目标?

4

3 回答 3

1

您可以使用bindUsing注释并提供您的自定义绑定代码以将 json 转换为要绑定的属性。

class Person {
    Long id
    String name

    @BindUsing({obj, source ->
       List retVal = [] 
       def aliases = source['aliases']
       if(aliases) {
           aliases.each { 
             retVal << new PersonAlias(name:it.name)
           }
       } 
       return retVal
    })
    List<PersonAlias> aliases

    static hasMany = [aliases: PersonAlias]
}
于 2015-03-27T08:03:42.340 回答
0

我也遇到了这个问题 - 我已尽力在我的网站上记录修复 - 请参阅http://dalelotts.com/software-architect/grails

一般来说,解决方案是将 JSON 转换为可用于数据绑定的参数映射。网站上的更多信息,包括 JSON 的注释驱动的 DomainClassMarshaller

protected Object readFromJson(Class type, InputStream entityStream, String charset) {

   def mapper = new ObjectMapper();
   def parsedJSON = mapper.readValue(entityStream, typeRef);

   Map<String, Object> map = new HashMap<>();

   parsedJSON.entrySet().each {Map.Entry<String, Object> entry ->
       if (List.isAssignableFrom(entry.getValue().getClass())) {

           List values = (List) entry.getValue();
           int limit = values.size()
           for (int i = 0; i <  limit; i++) {
               final theValue = values.get(i)
               map.put(entry.key + '[' + i + ']', theValue)

               appendMapValues(map, theValue, entry.key + '[' + i + ']' )

           }
       } else {
           map.put(entry.key, entry.value);
       }
   }

   def result = type.metaClass.invokeConstructor(map)


   // Workaround for http://jira.codehaus.org/browse/GRAILS-1984
   if (!result.id) {
       result.id = idFromMap(map)
   }
   result
}

private void appendMapValues(Map<String, Object> theMap, Object theValue, String prefix) {
    if (Map.isAssignableFrom(theValue.getClass())) {

        Map<String, Object> valueMap = (Map<String, Object>) theValue;

        for (Map.Entry<String, Object> valueEntry : valueMap.entrySet()) {
            theMap.put(prefix + '.' + valueEntry.key, valueEntry.value)
            appendMapValues(theMap, valueEntry.value, prefix + '.' + valueEntry.key)
        }
    }
}
于 2012-08-21T11:40:57.660 回答
0

我认为这个插件:https ://github.com/pedjak/grails-marshallers可能会满足您的需求?我自己还没有尝试过。

于 2012-08-07T05:06:49.677 回答