简体   繁体   中英

Groovy object with cycles as JSON

I am trying to use the default Json facilities to output an object as JSON. But unfortunately, the object in question actually has cycles in it. I need the JSON to either output #ref or simply prune it.

I have been working with the JsonGenerator and trying to define a custom converter that merely stops following an object serialization when it discovers something it has already encountered. I can't use a classic hashing structure because this would have the same problem: hence the use of an IdentityHashMap . Because I am basically trying to export a complicated structure from Jenkins I don't have the luxury knowing what field I can exclude (in fact, I am trying to determine what fields are available).

  1. The first approach below generates a NullPointerException because apparently it doesn't handle null values (that makes no sense because that's a pretty common case).
  2. So, I added excludeNulls() to the builder; same result.
  3. Since I don't care what the output is for that key, as long as it doesn't produce an error, it's fine. I simply hard coded it to "#ref" and, well, that's all I get!
  4. Then it occurred to me that, if it's not my case I should just delegate it to the original implementation. That continues to produce a stack overflow.

If the question isn't obvious, then it's this: How do you take the below map structure and get it to output JSON ; pruning cycles if needed but I don't really care how.

import groovy.json.JsonGenerator
import groovy.json.JsonGenerator.Converter

def loop = [
        loop: [:]
]

def thing = [
        foo:'hello',
        baz: [
                bat:loop
        ]
]
loop.loop = thing

new JsonGenerator.Options().addConverter(new Converter() {
    private seen = [:] as IdentityHashMap
    @Override
    boolean handles(Class<?> aClass) {
        true
    }

    @Override
    Object convert(Object o, String s) {
        if(! (seen[o]) && o){
            seen[o] = 'seen + o'
            o
        }
    }
}).build().toJson(thing).with { println(it)}

seems JsonGenerator thrown NPE

when Converter.convert(v,key) returns null on original non-null value...

import groovy.json.JsonGenerator
import groovy.json.JsonGenerator.Converter

def loop = [
        loop: [:]
]

def thing = [
        foo:'hello',
        baz: [
                bat:loop
        ],
        nnn: null
]
loop.loop = thing

new JsonGenerator.Options().addConverter(new Converter() {
    private seen = [:] as IdentityHashMap
    @Override
    boolean handles(Class<?> aClass) {
        true
    }

    @Override
    Object convert(Object o, String key) {
        if(o!=null){
            if( seen[o] ){
                //o = null //null instead of '<seen>' throws NPE
                o = '<seen>'
            }else{
                seen.put(o,true)
            }
        }
        return o
    }
}).build().toJson(thing).with { println(it)}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM