如何在Groovy中从列表动态构建闭包列表传入OrderBy?
解决Groovy动态生成OrderBy闭包列表的问题
问题分析
你遇到的MissingPropertyException是因为GroovyShell代码里犯了一个关键错误:"it".fieldName是在尝试访问字符串对象"it"的fieldName属性,而不是排序目标对象it的对应字段。字符串类本身没有这个属性,所以报错是必然的。
解决方案1:直接利用Groovy的动态属性访问(推荐)
其实完全不需要用GroovyShell来生成闭包,Groovy本身就支持灵活的动态属性访问,用下标或者getProperty就能轻松实现需求:
class Language { String name boolean dynamic String toString() { "name: $name, dynamic: $dynamic" } } def languages = [ new Language(name: 'Groovy', dynamic: true), new Language(name: 'Java', dynamic: false), new Language(name: 'Clojure', dynamic: true) ] // 动态字段列表 def sortFields = ['dynamic', 'name'] // 生成闭包列表:每个闭包捕获当前字段,通过下标访问属性 def closureList = sortFields.collect { field -> { it -> it[field] } } // 传入OrderBy使用 def orderBy = new OrderBy(closureList) def sortedLanguages = languages.sort(orderBy) // 输出验证 sortedLanguages.each { println it }
这段代码的核心是it[field]——Groovy允许用下标语法动态访问对象的属性,等价于it.getProperty(field)。每个闭包都会捕获当前迭代的field变量,确保排序时能正确访问对应属性。
解决方案2:正确使用GroovyShell动态生成闭包
如果你确实需要用GroovyShell的方式(比如处理更复杂的动态逻辑),需要修改闭包的生成方式,确保直接访问it的目标字段,而不是字符串的属性:
def sortFields = ['dynamic', 'name'] def sh = new GroovyShell() def closureList = sortFields.collect { field -> // 动态生成访问it.xxx的闭包代码 sh.evaluate("{ it -> it.$field }") } def orderBy = new OrderBy(closureList) def sortedLanguages = languages.sort(orderBy) sortedLanguages.each { println it }
这里通过字符串插值it.$field,让GroovyShell生成的闭包直接访问it的对应字段,避免了之前的字符串属性访问错误。
验证结果
两种方案运行后都会输出正确的排序结果:
name: Java, dynamic: false name: Clojure, dynamic: true name: Groovy, dynamic: true
内容的提问来源于stack exchange,提问作者Rao
相关产品推荐
相关产品推荐

