Grails - 如何让域类将JSON转换为域属性

问题描述:

我想教我的域类自动将JSON.parse(someJSON)的结果转换为也是自定义域类的成员。Grails - 如何让域类将JSON转换为域属性

鉴于这些领域类:

class Person { 
    Long id 
    String name 

    static hasMany = [aliases: PersonAlias] 
} 

class PersonAlias { 
    Person person 
    Long id 
    String name 
} 

和代表一些PersonAliases一个人这样JSON:

{ 
    "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) 
    } 
} 

但可悲的是我得到这个错误:

Failed to convert property value of type 'org.codehaus.groovy.grails.web.json.JSONArray' to required type 'java.util.Set' for property 'aliases'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [org.codehaus.groovy.grails.web.json.JSONObject] to required type [heavymeta.PersonAlias] for property 'aliases[0]': no matching editors or conversion strategy found

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

+0

Grails应该已经能够编组JSON。有一个需要在config.groovy中打开的设置。 – cdeszaq 2012-08-07 12:59:49

+0

Grails已经在一定程度上编组了JSON ......在上面的代码中,我找到了一个可行的Person对象,除了成员别名 – 2012-08-07 21:49:32

+0

,您是否找到了针对您的问题的解决方案? – 2013-02-26 06:53:39

可以使用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] 
} 

我认为这个插件:https://github.com/pedjak/grails-marshallers可能会做你想要的?虽然我没有尝试过。

+0

我喜欢那个插件,但它没有提供我要求的功能。它提供了一种替代方法来利用Grails现有的工具将对象编组为JSON。我需要将JSON转换为我的域类的实例。我有代码要这样做,但我想将其插入到我的域类中,以便它仅作为domainInstance.properties = convertedJSON的副作用发生。 – 2012-08-07 21:52:44

我也遇到这样的问题 - 我尽我所能来记录我的网站上修复 - 见http://dalelotts.com/software-architect/grails

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

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) 
     } 
    } 
}