All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sicheng.common.mapper.JsonMapper Maven / Gradle / Ivy

There is a newer version: 4.1.1
Show newest version
/**
 * 本作品使用 木兰公共许可证,第2版(Mulan PubL v2) 开源协议,请遵守相关条款,或者联系sicheng.net获取商用授权。
 * Copyright (c) 2016 SiCheng.Net
 * This software is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.sicheng.common.mapper;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

/**
 * 简单封装Jackson,实现JSON String<->Java Object的Mapper.
 * 封装不同的输出风格, 使用不同的builder函数创建实例.
 *
 * @author zhaolei
 * @version 2013-11-15
 */
public class JsonMapper extends ObjectMapper {

    private static final long serialVersionUID = 1L;

    private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);

    private static JsonMapper mapper;

    public JsonMapper() {
//		参数意义:
//		JsonInclude.Include.ALWAYS              默认
//		JsonInclude.Include.NON_DEFAULT     属性为默认值不序列化
//		JsonInclude.Include.NON_EMPTY         属性为 空(””) 或者为 NULL 都不序列化
//		JsonInclude.Include.NON_NULL           属性为NULL   不序列化

        //2020-01-26 由zhaolei从Include.NON_EMPTY 调整为Include.NON_NULL,
        //jackson从2.8.6升级到2.9.10后,空的List在序列时未能序列化。
        //通过修改达到:空的List序列化为{"arry":[]}的目标,这样才与广大的业务程序相匹配。
        this(Include.NON_NULL);
    }

    public JsonMapper(Include include) {
        // 设置输出时包含属性的风格
        if (include != null) {
            this.setSerializationInclusion(include);
        }
        // 允许单引号、允许不带引号的字段名称
        this.enableSimple();
        // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
        this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 空值处理为空串
        this.getSerializerProvider().setNullValueSerializer(new JsonSerializer() {
            @Override
            public void serialize(Object value, JsonGenerator jgen,
                                  SerializerProvider provider) throws IOException {
                jgen.writeString("");
            }
        });
        // zhaolei 2019-11-5 注释掉了以下代码,不应该进行HTML解码,这与防止xss攻击过滤器是有冲突的。
//		// 进行HTML解码。
//		this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer(){
//			@Override
//			public void serialize(String value, JsonGenerator jgen,
//					SerializerProvider provider) throws IOException,
//					JsonProcessingException {
//				jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
//			}
//		}));
        // 设置时区
        this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")
    }

    /**
     * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
     */
    public static JsonMapper getInstance() {
        if (mapper == null) {
            mapper = new JsonMapper().enableSimple();//允许单引号,允许不带引号的字段名称
        }
        return mapper;
    }

    /**
     * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
     */
    public static JsonMapper nonDefaultMapper() {
        if (mapper == null) {
            mapper = new JsonMapper(Include.NON_DEFAULT);
        }
        return mapper;
    }

    /**
     * Object可以是POJO,也可以是Collection或数组。
     * 如果对象为Null, 返回"null".
     * 如果集合为空集合, 返回"[]".
     */
    public String toJson(Object object) {
        try {
            return this.writeValueAsString(object);
        } catch (IOException e) {
            logger.warn("write to json string error:" + object, e);
            return null;
        }
    }

    /**
     * 反序列化POJO或简单Collection如List.
     * 

* 如果JSON字符串为Null或"null"字符串, 返回Null. * 如果JSON字符串为"[]", 返回空集合. *

* 如需反序列化复杂Collection如List, 请使用fromJson(String,JavaType) * * @see #fromJson(String, JavaType) */ public T fromJson(String jsonString, Class clazz) { if (StringUtils.isEmpty(jsonString)) { return null; } try { return this.readValue(jsonString, clazz); } catch (IOException e) { logger.warn("parse json string error:" + formatString(jsonString), e); return null; } } /** * 反序列化复杂Collection如List, 先使用函數createCollectionType构造类型,然后调用本函数. * * @see #createCollectionType(Class, Class...) */ @SuppressWarnings("unchecked") public T fromJson(String jsonString, JavaType javaType) { if (StringUtils.isEmpty(jsonString)) { return null; } try { return (T) this.readValue(jsonString, javaType); } catch (IOException e) { logger.warn("parse json string error:" + formatString(jsonString), e); return null; } } /** * 構造泛型的Collection Type如: * ArrayList, 则调用constructCollectionType(ArrayList.class,MyBean.class) * HashMap, 则调用(HashMap.class,String.class, MyBean.class) */ public JavaType createCollectionType(Class collectionClass, Class... elementClasses) { return this.getTypeFactory().constructParametricType(collectionClass, elementClasses); } /** * 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性. */ @SuppressWarnings("unchecked") public T update(String jsonString, T object) { try { return (T) this.readerForUpdating(object).readValue(jsonString); } catch (Exception e) { logger.warn("update json string:" + formatString(jsonString) + " to object:" + object + " error.", e); } return null; } /** * 輸出JSONP格式數據. */ public String toJsonP(String functionName, Object object) { return toJson(new JSONPObject(functionName, object)); } /** * 設定是否使用Enum的toString函數來讀寫Enum, * 為False時時使用Enum的name()函數來讀寫Enum, 默認為False. * 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用. */ public JsonMapper enableEnumUseToString() { this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); return this; } /** * 支持使用Jaxb的Annotation,使得POJO上的annotation不用与Jackson耦合。 * 默认会先查找jaxb的annotation,如果找不到再找jackson的。 */ public JsonMapper enableJaxbAnnotation() { JaxbAnnotationModule module = new JaxbAnnotationModule(); this.registerModule(module); return this; } /** * 允许单引号 * 允许不带引号的字段名称 */ public JsonMapper enableSimple() { this.configure(Feature.ALLOW_SINGLE_QUOTES, true); this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); return this; } /** * 取出Mapper做进一步的设置或使用其他序列化API. */ public ObjectMapper getMapper() { return this; } /** * 对象转换为JSON字符串 * * @param object * @return */ public static String toJsonString(Object object) { return JsonMapper.getInstance().toJson(object); } /** * JSON字符串转换为对象 * * @param jsonString * @param clazz * @return */ public static Object fromJsonString(String jsonString, Class clazz) { return JsonMapper.getInstance().fromJson(jsonString, clazz); } /** * 方法说明:把长字符串截短,便于在日志中输出 * * @param jsonString * @return java.lang.String * @author zhalei * @version 2020-01-28 22:51 */ private String formatString(String jsonString) { if (jsonString != null || jsonString.length() > 50) { jsonString = jsonString.substring(0, 50) + "..."; return jsonString; } return jsonString; } /** * 测试 */ public static void main(String[] args) { List> list = Lists.newArrayList(); Map map = Maps.newHashMap(); map.put("id", 1); map.put("pId", -1); map.put("name", "根节点"); map.put("empty1", ""); map.put("empty2", null); map.put("arry", Lists.newArrayList());//空的ArrayList list.add(map); map = Maps.newHashMap(); map.put("id", 2); map.put("pId", 1); map.put("name", "你好"); map.put("open", true); list.add(map); String json = JsonMapper.getInstance().toJson(list); System.out.println(json); } }