使用Groovy中的JSONBuilder排除空值

6

是否有可能使用默认的JsonBuilder库在Groovy中创建JSON值,以排除对象中的所有null值?就像Java中的Jackson通过注释类来排除null值一样。

例如:

{
   "userId": "25",
   "givenName": "John",
   "familyName": null,
   "created": 1360080426303
}

应该打印为:

{
   "userId": "25",
   "givenName": "John",
   "created": 1360080426303
}

你需要它是递归的吗? - Will
@WillP 是的。因为它可能在对象中嵌入了列表或映射。 - Peymankh
你在嵌套结构中使用闭包语法还是映射语法? - Will
@WillP 目前我正在使用 map 语法,但如果可能的话可以切换到闭包。 - Peymankh
4个回答

8

不确定我的方法是否适用于你,因为它是在一个具有列表属性的 Map 上运作:

def map = [a:"a",b:"b",c:null,d:["a1","b1","c1",null,[d1:"d1",d2:null]]]

def denull(obj) {
  if(obj instanceof Map) {
    obj.collectEntries {k, v ->
      if(v) [(k): denull(v)] else [:]
    }
  } else if(obj instanceof List) {
    obj.collect { denull(it) }.findAll { it != null }
  } else {
    obj
  }
}

println map
println denull(map)

yields:

[a:a, b:b, c:null, d:[a1, b1, c1, null, [d1:d1, d2:null]]]
[a:a, b:b, d:[a1, b1, c1, [d1:d1]]]

在过滤掉null值之后,您可以将Map渲染为JSON。


这是一个不错的答案,但更好的方法是用 Collection 替换 List。这样所有元素,包括 Set 都将被去掉空值! - Peymankh
谢谢你的回答,@chanwit,非常有帮助! - Vishal Biyani

3

如果您使用的是Groovy >2.5.0版本,您可以使用JsonGenerator。下面的示例取自2018年7月份的Groovy文档

class Person {
    String name
    String title
    int age
    String password
    Date dob
    URL favoriteUrl
}

Person person = new Person(name: 'John', title: null, age: 21, password: 'secret',
                            dob: Date.parse('yyyy-MM-dd', '1984-12-15'),
                            favoriteUrl: new URL('http://groovy-lang.org/'))

def generator = new JsonGenerator.Options()
    .excludeNulls()
    .dateFormat('yyyy@MM')
    .excludeFieldsByName('age', 'password')
    .excludeFieldsByType(URL)
    .build()

assert generator.toJson(person) == '{"dob":"1984@12","name":"John"}'

2
我使用了Groovy的metaClass来解决这个问题,但不确定它是否适用于所有情况。
我创建了一个类来保存所需的元素,但省略了可能为空(或空白)值的可选元素。
private class User {
    def id
    def username
}

然后,我将数据添加到这个类中。我的用例相当复杂,因此这只是一个简化版本,只是为了展示我所做的事情的一个示例:

User a = new User(id: 1, username: 'john')
User b = new User(id: 2, username: 'bob')
def usersList = [a,b]

usersList.each { u ->
    if (u.id == 1)
        u.metaClass.hobbies = ['fishing','skating']
}
def jsonBuilder = new JsonBuilder([users: usersList])
println jsonBuilder.toPrettyString()

结果:

{
"users": [
    {
        "id": 1,
        "username": "john",
        "hobbies": [
            "fishing",
            "skating"
        ]
    },
    {
        "id": 2,
        "username": "bob"
    }
  ]
}

1
如果您不需要使用JSONBuilder,可以使用com.fasterxml.jackson:
创建对象:
private static final ObjectMapper JSON_MAPPER = new ObjectMapper().with {
    setSerializationInclusion(JsonInclude.Include.NON_NULL)
    setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
    setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
    setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
}

并像这样显示您的地图列表(地图中可以包含任何对象):
println(JSON_MAPPER.writeValueAsString(listOfMaps))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接