/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.common.utils;

import com.crunii.micro.common.jackson.DateModule;
import com.crunii.micro.common.jackson.URIModule;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

/**
 * <pre>
 * 	方法完全重构，优化实现方法
 * </pre>
 *
 * @author 田平 create 2019年2月21日上午11:06:19
 */
public class JsonUtil {
	private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);

	private static ObjectMapper jsonMapper = new ObjectMapper();

	static {
		jsonMapper.registerModule(new DateModule());
		jsonMapper.registerModule(new URIModule());
		Hibernate5Module hModule = new Hibernate5Module();
		hModule.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
		jsonMapper.registerModule(hModule);
		jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		jsonMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
		jsonMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
//		jsonMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);//大小写不敏感
	}

	public static synchronized ObjectMapper getMapper() {
		return jsonMapper;
	}

	/**
	 * <pre>
	 * 	 对象嵌套泛型的使用这个方法
	 * </pre>
	 *
	 * @param json
	 * @param valueTypeRef
	 * @return
	 */
	public static <T> T jsonToObject(String json, TypeReference<T> valueTypeRef) {
		if (StringUtils.hasText(json)) {
			try {
				return jsonMapper.readValue(json, valueTypeRef);
			} catch (Exception e) {
				throw new RuntimeException("json字符串转换Object出错！", e);
			}
		} else {
			return null;
		}
	}

	public static Map<String, Object> jsonToMap(String jsonString) {
		Map<String, Object> map = null;
		if (StringUtils.hasText(jsonString)) {
			try {
				TypeReference<Map<String, Object>> tr = new TypeReference<Map<String, Object>>() {};
				map = jsonMapper.readValue(jsonString, tr);
			} catch (Exception e) {
				throw new RuntimeException("json字符串转换Map出错！", e);
			}
		}
		return map;
	}

	public static Map<String, String> jsonToMapStr(String jsonString) {

		Map<String, String> map = null;
		if (StringUtils.hasText(jsonString)) {
			try {
				TypeReference<Map<String, String>> tr = new TypeReference<Map<String, String>>() {};
				map = jsonMapper.readValue(jsonString, tr);
			} catch (Exception e) {
				throw new RuntimeException("json字符串转换Map出错！", e);
			}
		}
		return map;

	}

	public static String getJsonString(Object value) {
		String jsonString = null;
		if (value != null) {
			try {
				jsonString = jsonMapper.writeValueAsString(value);
			} catch (Exception e) {
				throw new RuntimeException("java对象转换为json字符串出错！", e);
			}
		}
		return jsonString;
	}

	public static String getPrettyJsonString(Object value) {
		String jsonString = null;
		if (value != null) {
			try {
				jsonString = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);
			} catch (Exception e) {
				throw new RuntimeException("java对象转换为json字符串完美格式化输出错误！", e);
			}
		}
		return jsonString;
	}

	public static <T> List<T> jsonToList(String json, Class<T> genericType) {
		if (StringUtils.hasText(json)) {
			List<T> list = null;
			try {
				JavaType javaType = jsonMapper.getTypeFactory().constructParametricType(List.class, genericType);
				list = jsonMapper.readValue(json, javaType);
				return list;
			} catch (Exception e) {
				log.error("json string to JsonNode error,please check json string!json{}", json, e);
				throw new RuntimeException("json string to JsonNode error,please check json string!");
			}
		} else {
			return null;
		}

	}

	public static <T> T[] jsonToArray(String json, Class<T> genericType) {
		if (StringUtils.hasText(json)) {
			T[] array = null;
			try {
				JavaType javaType = jsonMapper.getTypeFactory().constructArrayType(genericType);
				array = jsonMapper.readValue(json, javaType);
				return array;
			} catch (Exception e) {
				log.error("json string to JsonNode error,please check json string!json:{}", json, e);
				throw new RuntimeException("json string to JsonNode error,please check json string!");
			}
		} else {
			return null;
		}
	}

	public static <T> T jsonToObject(String json, Class<T> objClass, Class<?>... genericType) {
		if (StringUtils.hasText(json)) {
			T t = null;
			try {
				JavaType javaType = jsonMapper.getTypeFactory().constructParametricType(objClass, genericType);
				t = jsonMapper.readValue(json, javaType);
				return t;
			} catch (Exception e) {
				log.error("json string to JsonNode error,please check json string!json:{}", json, e);
				throw new RuntimeException("json string to JsonNode error,please check json string!");
			}
		} else {
			return null;
		}
	}

}
