Groovy json 包

学习任何一门语言,我都看重 json 的操作是否顺手方便,毕竟 json 是现在最流行的数据交换格式。

JsonOutput

官方定义:

一个提供 JSON 结构的字符串序列化类,可以将各种类型变成字符串,但不提供自定义结果输出的能力,如果需要更改结果输出的能力可以使用下面会提到的 JsonGenerator

def list = [1,2,4,5]
def json = JsonOutput.toJson(list)
println json
println JsonOutput.prettyPrint(json)

输出:

[1,2,4,5]
[
    1,
    2,
    4,
    5
]

源码

使用了一个默认的JsonGenerator来提供 json 能力

static final JsonGenerator DEFAULT_GENERATOR = new DefaultJsonGenerator(new JsonGenerator.Options());

    public static String toJson(Object object) {
        return DEFAULT_GENERATOR.toJson(object);
    }

    /**
     * @return a JSON object representation for a map
     */
    public static String toJson(Map m) {
        return DEFAULT_GENERATOR.toJson(m);
    }

JsonGenerator

官方定义:

从对象生成 Json,JsonGenerator.Options 构建器可用于配置 JsonGenerator 的实例。(自定义)

源码

public interface JsonGenerator {

    /**
     * 将一个对象转换成JSON字符串.
     *
     * @param object to convert to JSON
     * @return JSON
     */
    String toJson(Object object);

    /**
     * 判断配置是否排除了给定的这个字段
     * 
     * @param name of the field
     * @return true if that field is being excluded, else false
     */
    boolean isExcludingFieldsNamed(String name);

    /**
     * 判断配置是否排除了给定的这个值
     *
     * @param value an instance of an object
     * @return true if values like this are being excluded, else false
     */
    boolean isExcludingValues(Object value);

    /**
     * 处理类型转换
     *
     * @since 2.5.0
     */
    interface Converter {

        /**
         * 给定一个类型,如果这个类型能被转换器处理,那么返回true
         * @param type the type of the object to convert
         * @return {@code true} if this converter can successfully convert values of
         *      the given type, else {@code false}
         */
        boolean handles(Class<?> type);

        /**
         * 进行对象转换
         *
         * @param value the object to convert
         * @param key the key name for the value, may be {@code null}
         * @return the converted object
         */
        Object convert(Object value, String key);

    }

    /**
     * A builder used to construct a {@link JsonGenerator} instance that allows
     * control over the serialized JSON output.  If you do not need to customize the
     * output it is recommended to use the static {@code JsonOutput.toJson} methods.
     *
     */
    class Options {

        protected static final String JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH🇲🇲ssZ";
        protected static final Locale JSON_DATE_FORMAT_LOCALE = Locale.US;
        protected static final String DEFAULT_TIMEZONE = "GMT";

        protected boolean excludeNulls;
        protected boolean disableUnicodeEscaping;
        protected String dateFormat = JSON_DATE_FORMAT;
        protected Locale dateLocale = JSON_DATE_FORMAT_LOCALE;
        protected TimeZone timezone = TimeZone.getTimeZone(DEFAULT_TIMEZONE);
        protected final Set<Converter> converters = new LinkedHashSet<Converter>();
        protected final Set<String> excludedFieldNames = new HashSet<String>();
        protected final Set<Class<?>> excludedFieldTypes = new HashSet<Class<?>>();

        public Options() {}

        /**
         * 不序列化null值
         *
         * @return a reference to this {@code Options} instance
         */
        public Options excludeNulls() {
            excludeNulls = true;
            return this;
        }

        /**
         * Disables the escaping of Unicode characters in JSON String values.
         *
         * @return a reference to this {@code Options} instance
         */
        public Options disableUnicodeEscaping() {
            disableUnicodeEscaping = true;
            return this;
        }

        /**
         * Sets the date format that will be used to serialize {@code Date} objects.
         * This must be a valid pattern for {@link java.text.SimpleDateFormat} and the
         * date formatter will be constructed with the default locale of {@link Locale#US}.
         *
         * @param format date format pattern used to serialize dates
         * @return a reference to this {@code Options} instance
         * @exception NullPointerException if the given pattern is null
         * @exception IllegalArgumentException if the given pattern is invalid
         */
        public Options dateFormat(String format) {
            return dateFormat(format, JSON_DATE_FORMAT_LOCALE);
        }

        /**
         * Sets the date format that will be used to serialize {@code Date} objects.
         * This must be a valid pattern for {@link java.text.SimpleDateFormat}.
         *
         * @param format date format pattern used to serialize dates
         * @param locale the locale whose date format symbols will be used
         * @return a reference to this {@code Options} instance
         * @exception IllegalArgumentException if the given pattern is invalid
         */
        public Options dateFormat(String format, Locale locale) {
            // validate date format pattern
            new SimpleDateFormat(format, locale);
            dateFormat = format;
            dateLocale = locale;
            return this;
        }

        /**
         * Sets the time zone that will be used to serialize dates.
         *
         * @param timezone used to serialize dates
         * @return a reference to this {@code Options} instance
         * @exception NullPointerException if the given timezone is null
         */
        public Options timezone(String timezone) {
            this.timezone = TimeZone.getTimeZone(timezone);
            return this;
        }

        /**
         * Registers a converter that will be called when a type it handles is encountered.
         *
         * @param converter to register
         * @return a reference to this {@code Options} instance
         */
        public Options addConverter(Converter converter) {
            if (converter != null) {
                converters.add(converter);
            }
            return this;
        }

        /**
         * Registers a closure that will be called when the specified type or subtype
         * is serialized.
         *
         * <p>The closure must accept either 1 or 2 parameters.  The first parameter
         * is required and will be instance of the {@code type} for which the closure
         * is registered.  The second optional parameter should be of type {@code String}
         * and, if available, will be passed the name of the key associated with this
         * value if serializing a JSON Object.  This parameter will be {@code null} when
         * serializing a JSON Array or when there is no way to determine the name of the key.
         *
         * <p>
         * Example:
         * <pre><code class="groovyTestCase">
         *     def generator = new groovy.json.JsonGenerator.Options()
         *                         .addConverter(URL) { URL u {@code ->}
         *                             u.getHost()
         *                         }
         *                         .build()
         *
         *     def input = [domain: new URL('http://groovy-lang.org/json.html#_parser_variants')]
         *
         *     assert generator.toJson(input) == '{"domain":"groovy-lang.org"}'
         * </code></pre>
         *
         * <p>If two or more closures are registered for the exact same type the last
         * closure based on the order they were specified will be used.  When serializing an
         * object its type is compared to the list of registered types in the order the were
         * given and the closure for the first suitable type will be called.  Therefore, it is
         * important to register more specific types first.
         *
         * @param type the type to convert
         * @param closure called when the registered type or any type assignable to the given
         *                type is encountered
         * @param <T> the type this converter is registered to handle
         * @return a reference to this {@code Options} instance
         * @exception NullPointerException if the given type or closure is null
         * @exception IllegalArgumentException if the given closure does not accept
         *                  a parameter of the given type
         */
        public <T> Options addConverter(Class<T> type,
                                        @ClosureParams(value=FromString.class, options={"T","T,String"})
                                        Closure<?> closure)
        {
            Converter converter = new DefaultJsonGenerator.ClosureConverter(type, closure);
            converters.remove(converter);
            return addConverter(converter);
        }

        /**
         * Excludes from the output any fields that match the specified names.
         *
         * @param fieldNames name of the field to exclude from the output
         * @return a reference to this {@code Options} instance
         */
        public Options excludeFieldsByName(CharSequence... fieldNames) {
            return excludeFieldsByName(Arrays.asList(fieldNames));
        }

        /**
         * Excludes from the output any fields that match the specified names.
         *
         * @param fieldNames collection of names to exclude from the output
         * @return a reference to this {@code Options} instance
         */
        public Options excludeFieldsByName(Iterable<? extends CharSequence> fieldNames) {
            for (CharSequence cs : fieldNames) {
                if (cs != null) {
                    excludedFieldNames.add(cs.toString());
                }
            }
            return this;
        }

        /**
         * Excludes from the output any fields whose type is the same or is
         * assignable to any of the given types.
         *
         * @param types excluded from the output
         * @return a reference to this {@code Options} instance
         */
        public Options excludeFieldsByType(Class<?>... types) {
            return excludeFieldsByType(Arrays.asList(types));
        }

        /**
         * Excludes from the output any fields whose type is the same or is
         * assignable to any of the given types.
         *
         * @param types collection of types to exclude from the output
         * @return a reference to this {@code Options} instance
         */
        public Options excludeFieldsByType(Iterable<Class<?>> types) {
            for (Class<?> c : types) {
                if (c != null) {
                    excludedFieldTypes.add(c);
                }
            }
            return this;
        }

        /**
         * Creates a {@link JsonGenerator} that is based on the current options.
         *
         * @return a fully configured {@link JsonGenerator}
         */
        public JsonGenerator build() {
            return new DefaultJsonGenerator(this);
        }
    }

}

使用

static void main(String[] args) {
        def list = ["name": "wang", "age": 99,"list":[1,2,3,4]]
        def build = new JsonGenerator.Options()
                .excludeFieldsByType(Number) //排除数字类型的字段
                .excludeFieldsByName('name') //排除字段名为name的字段
                .addConverter(List) { List u -> //添加一个转换器 将List类型的字段转换成取List第一个值
                    u.get(0)
                }
                .build()
        println build.toJson(list)
    }


// 结果
// {"list":1}

JsonBuilder

通过简单语法来构造 json 对象,在 groovy 里面不想再用 fastjson 了嗷

使用

static void main(String[] args) {
                def exp = '''{
    "x": {
        "person": {
            "firstName": "Guillame",
            "lastName": "Laforge",
            "address": {
                "city": "Paris",
                "country": "France",
                "zip": {
                    "af": "a"
                }
            },
            "married": true,
            "conferences": [
                {
                    "a": "JavaOne"
                },
                {
                    "a": "Gr8conf"
                }
            ]
        }
    }
}'''
        def builder = new groovy.json.JsonBuilder()
         builder.x {
            person {
                firstName 'Guillame'
                lastName 'Laforge'
                // Named arguments are valid values for objects too
                address {
                    city 'Paris'
                    country 'France'
                    zip {
                      af 'a'
                    }
                }
                married true
                // a list of values
                conferences {a 'JavaOne'} {a 'Gr8conf'}
            }
        }
        println builder.toPrettyString()
        assert  builder.toPrettyString() == exp
    }

JsonSlurper

让我们方便的操纵 json

使用

static void main(String[] args) {
        def builder = new JsonBuilder()
        builder.x {
            person {
                firstName 'Guillame'
                lastName 'Laforge'
                // Named arguments are valid values for objects too
                address {
                    city 'Paris'
                    country 'France'
                    zip {
                        af 'a'
                    }
                }
                married true
                // a list of values
                conferences {a 'JavaOne'} {a 'Gr8conf'}
            }
        }
        def json = builder.toString()
        def res = new JsonSlurper().parseText(json)
        println res.x.person.conferences[1].a

    }