/* * Copyright 2019 wjybxx * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wjybxx.fastjgame.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.apache.commons.lang3.exception.ExceptionUtils; import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Map; /** * Json工具类(字符集UTF-8)。 * <p> * <p> * 最终还是选择了Jackson。 * 建议:Gson也可以一用,但是最好不要使用FastJson,fastJson生成的json格式并不标准,有兼容性问题,此外代码质量不好。 * jackson的代码质量真的很不错,扩展性很好。 * <p> * )_( jackson也有坑的一点,主要在final字段上。 * <p> * 这些方法真的很强大易用: * {@link TypeFactory#constructMapType(Class, Class, Class)} * {@link TypeFactory#constructArrayType(Class)} * {@link TypeFactory#constructCollectionType(Class, Class)} * <p> * 简单运用: * {@link #readMapFromJson(String, Class, Class, Class)} * * @author wjybxx * @version 1.0 * date - 2019/7/12 23:05 * github - https://github.com/hl845740757 */ public class JsonUtils { /** * ObjectMapper自称自己是线程安全的,但是好像还是有点bug */ private static final ThreadLocal<ObjectMapper> MAPPER_THREAD_LOCAL = ThreadLocal.withInitial(ObjectMapper::new); /** * 一定要私有,不可以暴露给外层,否则会导致应用程序对{@code Jackson}产生强依赖 */ private static ObjectMapper getMapper() { return MAPPER_THREAD_LOCAL.get(); } // ---------------------------------- 基本支持 --------------------------- /** * 将bean转换为json字符串 */ public static String writeAsJson(@Nonnull Object bean) { try { return getMapper().writeValueAsString(bean); } catch (JsonProcessingException e) { // 之所以捕获,是因为,出现异常的地方应该是非常少的 return ExceptionUtils.rethrow(e); } } /** * 解析json字符串为java对象。 */ public static <T> T readFromJson(@Nonnull String json, @Nonnull Class<T> clazz) { try { return getMapper().readValue(json, clazz); } catch (IOException e) { return ExceptionUtils.rethrow(e); } } /** * 将bean转换为json对应的字节数组 */ public static byte[] writeAsJsonBytes(@Nonnull Object bean) { try { return getMapper().writeValueAsBytes(bean); } catch (JsonProcessingException e) { return ExceptionUtils.rethrow(e); } } /** * 解析json字符串对应的字节数组为java对象。 */ public static <T> T readFromJsonBytes(@Nonnull byte[] jsonBytes, @Nonnull Class<T> clazz) { try { return getMapper().readValue(jsonBytes, clazz); } catch (IOException e) { return ExceptionUtils.rethrow(e); } } // ---------------------------------- Map支持 --------------------------- /** * 解析json字符串为map对象。 */ public static <M extends Map> M readMapFromJson(@Nonnull String json, @Nonnull Class<M> mapClass, @Nonnull Class<?> keyClass, @Nonnull Class<?> valueClass) { ObjectMapper mapper = getMapper(); MapType mapType = mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass); try { return mapper.readValue(json, mapType); } catch (IOException e) { return ExceptionUtils.rethrow(e); } } /** * 解析json字符串的字节数组为map对象。 */ public static <M extends Map<?, ?>> M readMapFromJsonBytes(@Nonnull byte[] jsonBytes, @Nonnull Class<M> mapClass, @Nonnull Class<?> keyClass, @Nonnull Class<?> valueClass) { ObjectMapper mapper = getMapper(); MapType mapType = mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass); try { return mapper.readValue(jsonBytes, mapType); } catch (IOException e) { return ExceptionUtils.rethrow(e); } } // ---------------------------------------- 输入输出流支持 ------------------------------- public static void writeToOutputStream(OutputStream out, Object value) { try { getMapper().writeValue(out, value); } catch (IOException e) { ExceptionUtils.rethrow(e); } } public static <T> T readFromInputStream(InputStream in, Class<T> clazz) { try { return getMapper().readValue(in, clazz); } catch (IOException e) { return ExceptionUtils.rethrow(e); } } public static void main(String[] args) { Int2IntMap data = new Int2IntOpenHashMap(); data.put(1, 5); data.put(6, 7); String json = writeAsJson(data); System.out.println("json = " + json); Int2IntMap rData = readMapFromJson(json, Int2IntOpenHashMap.class, Integer.class, Integer.class); System.out.println("map = " + rData); System.out.println("equals = " + data.equals(rData)); } }