我想教我的域类自动将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]到必需的类型 [heavymeta.PersonAlias]属性'aliases [0]':没有匹配的编辑器 或发现转换策略
所以,我想教我的域类如何自动将JSON数据转换为PersonAlias实例。我想避免在将数据传递给Domain对象之前格式化控制器中的数据。我如何实现这些目标?
答案 0 :(得分: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]
}
答案 1 :(得分:0)
我认为这个插件:https://github.com/pedjak/grails-marshallers可能正在寻找你想要的东西吗?我自己没试过。
答案 2 :(得分: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)
}
}
}