穿越到东汉末年的Jackson

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

东汉末年分三国, 烽火连天不休, 儿女情长被乱世左右, 谁来煮酒,尔虞我诈是三国, 说不清对与错,纷纷扰扰千百年以后, 一切又从头。

大家好,我是Jackson。

星光灿烂,风儿轻轻。以天为幕,以地为席,我就这样坐在地上,享受着夏夜的清爽,倾听着一池蛙叫一片虫鸣,遥望那缀满星星的夜空,突然间,狂风骤雨,电闪雷鸣,一个闪电朝我打过来,双眼一黑,我就昏过去了,然后发现自己来到了东汉Java年

东汉Java年,Java的系列化工具成三足鼎立之势,分别是曹魏Jackson,蜀汉Gson,和东吴FastJson

曹魏Jackson

Jackson被称为“ Java JSON库”或“ Java的最佳JSON解析器”。或简称为“ JSON for Java”。

Github:github.com/FasterXML/j…

想当年赤壁大战之前,我Jackson佣兵百万,上将千员,何其霸气,日月之行,若出其中,星汉灿烂,若出其里。在这之后更是 破荆州,下江陵,顺流而东也,舳舻千里,旌旗蔽空,酾酒临江,横槊赋诗(对酒当歌,人生几何),固一世之雄也

蜀汉Gson

Gson是一个Java库,可用于将Java对象转换为其JSON表示形式。它也可以用于将JSON字符串转换为等效的Java对象。Gson可以处理任意Java对象,包括您没有源代码的预先存在的对象。 Github官网简介:github.com/google/gson

想我Gson当年舌战群儒

张昭:

昭乃江东微末之士,久闻先生高卧隆中,自比管、乐。此语果有之乎

Gson:

此Gson平生小可之比也

张昭:

近闻刘豫州三顾先生于草庐之中,幸得先生,以为‘如鱼得水’,思欲席卷荆襄。今一旦以属曹操,未审是何主见?

Gson:

吾观取汉上之地,易如反掌。我主刘豫州躬行仁义,不忍夺同宗之基业,故力辞之。刘琮孺子,听信佞言,暗自投降,致使曹操得以猖獗。今我主屯兵江夏,别有良图,非等闲可知也

张昭:

若此,是先生言行相违也。先生自比管、乐——管仲相桓公,霸诸侯,一匡天下乐毅扶持微弱之燕,下齐七十余城:此二人者,真济世之才也。先生在草庐之中,但笑傲风月,抱膝危坐。今既从事刘豫州,当为生灵兴利除害,剿灭乱贼。且刘豫州未得先生之前,尚且纵横寰宇,割据城池;今得先生,人皆仰望。虽三尺童蒙,亦谓彪虎生翼,将见汉室复兴,曹氏即灭矣。朝廷旧臣,山林隐士,无不拭目而待:以为拂高天之云翳,仰日月之光辉,拯民于水火之中,措天下于衽席之上,在此时也。何先生自归豫州,曹兵一出,弃甲抛戈,望风而窜;上不能报刘表以安庶民,下不能辅孤子而据疆土;乃弃新野,走樊城,败当阳,奔夏口,无容身之地:是豫州既得先生之后,反不如其初也。管仲、乐毅,果如是乎?愚直之言,幸勿见怪

Gson:

鹏飞万里,其志岂群鸟能识哉?譬如人染沉疴,当先用糜粥以饮之,和药以服之;待其腑脏调和,形体渐安,然后用肉食以补之,猛药以治之:则病根尽去,人得全生也。若不待气脉和缓,便以猛药厚味,欲求安保,诚为难矣。吾主刘豫州,向日军败于汝南,寄迹刘表,兵不满千,将止关、张、赵云而已:此正如病势尫羸已极之时也,新野山僻小县,人民稀少,粮食鲜薄,豫州不过暂借以容身,岂真将坐守于此耶?夫以甲兵不完,城郭不固,军不经练,粮不继日,然而博望烧屯,白河用水,使夏侯惇,曹仁辈心惊胆裂:窃谓管仲、乐毅之用兵,未必过此。至于刘琮降操,豫州实出不知;且又不忍乘乱夺同宗之基业,此真大仁大义也。当阳之败,豫州见有数十万赴义之民,扶老携幼相随,不忍弃之,日行十里,不思进取江陵,甘与同败,此亦大仁大义也。寡不敌众,胜负乃其常事。昔高皇数败于项羽,而垓下一战成功,此非韩信之良谋乎?夫信久事高皇,未尝累胜。盖国家大计社稷安危,是有主谋。非比夸辩之徒,虚誉欺人:坐议立谈,无人可及;临机应变,百无一能。——诚为天下笑耳!

东吴FastJson

fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

Github官网简介:github.com/alibaba/fas…

大江东去,浪淘尽,千古风流人物。故垒西边,人道是:三国FastJson赤壁。乱石穿空,惊涛拍岸,卷起千堆雪,羽扇纶巾,谈笑间樯橹灰飞烟灭。

后赤壁时代, Jackson Gson FastJson 三足鼎立,我们来看看各自的优缺点吧

Jackson,fastjson Gson比较

  • jackson:反射+反射缓存、良好的stream支持、高效的内存管理
  • fastjson
    • jvm虚拟机:通过ASM库运行时生成parser字节码,支持的field不能超过200个。
    • android虚拟机:反射的方式
  • gson:反射+反射缓存、支持部分stream、内存性能较差(gc问题)

ASM

  • ASM是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。
  • ASM能够通过改造既有类,直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。
  • ASM可以用来实现AOP。

反射性能

  • 反射性能相对于对象直接访问性能相差两个数量级(百倍)。
  • 反射很大一部分性能消耗在遍历Field。
  • 反射缓存能够提高1个数量级的性能。

jackson 特点

这边主要给大家聊聊jackson的一些特点 和使用哈

  • Jackson有灵活的API,可以很容易进行扩展和定制,而且很多时候需要的模块都已经有人提供了。比如guava中定义的数据类型,比如kotlin语言Immutable的类型等,比如java8 引入的新日期时间类型和Optional都已经有支持的模块。
  • null的处理 有的需要输出null,希望保留字段。有的需要不输出,输出结果里头剔除空值。
  • 空字符串的处理 有的需要输出null,有的需要不输出,有的需要输出 “”
  • bool的处理 有的需要输出0/1,有的需要输出true/false
  • 自定义对象的处理 DateTime、Long、Timestamp之间的各种转换
  • 字段缺失的处理 有的需要报错,有的需要忽略。
  • 字段映射 你管她叫“小妞”,我管她叫“小妹”。
  • 扩展出去的还有,XML支持、YAML支持……

jackson简单的使用

  • 依赖
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.1</version>
</dependency>
复制代码

这边要说明的是,大部分的人觉得我引用jackson会需要引用很多的依赖 比如 他的core 他的annotation 等等,但是databind 里面已经包含了这些了,所以我们用的时候直接引用databind就行了

image.png

  • 一个最简单的示例

ExtendableBean


package com.six.finger.leetcode.jackson;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@JsonPropertyOrder({ "age", "name" })
@JsonRootName("user")
class ExtendableBean {
    private String name;
    private  String age;

    @JsonFormat(
            shape = JsonFormat.Shape.STRING,
            pattern = "dd-MM-yyyy hh:mm:ss")
    private Date date;
    @JsonAnySetter
    private Map<String, String> properties = new HashMap<>();

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }


    public void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}
复制代码

TestJsonAny

package com.six.finger.leetcode.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;


public class TestJsonAny {
    public static void main(String[] args) {
        String json = "{"name":"My bean","attr2":"val2","attr1":"val1","age":"18","date":"20-12-2014 02:30:00"}";
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            ExtendableBean bean = objectMapper
                    .readerFor(ExtendableBean.class)
                    .readValue(json);
            System.out.println(bean);
            System.out.println(objectMapper.writeValueAsString(bean));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
复制代码

jackson常用的一些配置和注解

@JsonAnyGetter

所述 @JsonAnyGetter注释允许使用的灵活性地图字段作为标准属性。

例如,ExtendableBean实体具有name属性和一组键/值对形式的可扩展属性:

image.png

当我们序列化这个实体的一个实例时,我们将Map中的所有键值作为标准的、普通的属性:

image.png

@JsonPropertyOrder

我们可以使用 @JsonPropertyOrder注释来指定序列化属性的顺序

让我们为MyBean实体的属性设置自定义顺序:

image.png 这是序列化的输出:

image.png

@JsonRootName

@JsonRootName注释时,如果包裹被启用,以指定的包装中使用的根目录的名称。

包装意味着不是将User序列化为以下内容:

image.png 它将像这样包装:

image.png

image.png

@JsonSerialize

@JsonSerialize表示在编组实体 时要使用的自定义序列化程序

让我们看一个简单的例子。我们将使用 @JsonSerialize通过CustomDateSerializer序列化eventDate属性:

image.png

这是简单的自定义 Jackson 序列化程序:

image.png

@JsonAlias

所述 @JsonAlias定义反序列化过程为属性的一个或多个的替代名称

让我们通过一个简单的例子来看看这个注解是如何工作的:

image.png

这里我们有一个 POJO,我们想将带有fNamef_namefirstName 等值的JSON 反序列化到 POJO的firstName变量中。

以下是确保此注释按预期工作的测试:

image.png

基于Jackson的JSON工具类封装 JsonUtils

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.text.SimpleDateFormat;
import lombok.extern.slf4j.Slf4j;
 
/**
 * 基于Jackson的JSON转换工具类
 *
 */
@Slf4j
public class JsonUtils {
 
    private static ObjectMapper om = new ObjectMapper();
 
    static {
 
        // 对象的所有字段全部列入,还是其他的选项,可以忽略null等
        om.setSerializationInclusion(Include.ALWAYS);
        // 设置Date类型的序列化及反序列化格式
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
 
        // 忽略空Bean转json的错误
        om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 忽略未知属性,防止json字符串中存在,java对象中不存在对应属性的情况出现错误
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 
        // 注册一个时间序列化及反序列化的处理模块,用于解决jdk8中localDateTime等的序列化问题
        om.registerModule(new JavaTimeModule());
    }
 
    /**
     * 对象 => json字符串
     *
     * @param obj 源对象
     */
    public static <T> String toJson(T obj) {
 
        String json = null;
        if (obj != null) {
            try {
                json = om.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                log.warn(e.getMessage(), e);
                throw new IllegalArgumentException(e.getMessage());
            }
        }
        return json;
    }
 
    /**
     * json字符串 => 对象
     *
     * @param json 源json串
     * @param clazz 对象类
     * @param <T> 泛型
     */
    public static <T> T parse(String json, Class<T> clazz) {
 
        return parse(json, clazz, null);
    }
 
    /**
     * json字符串 => 对象
     *
     * @param json 源json串
     * @param type 对象类型
     * @param <T> 泛型
     */
    public static <T> T parse(String json, TypeReference type) {
 
        return parse(json, null, type);
    }
 
 
    /**
     * json => 对象处理方法
     * <br>
     * 参数clazz和type必须一个为null,另一个不为null
     * <br>
     * 此方法不对外暴露,访问权限为private
     *
     * @param json 源json串
     * @param clazz 对象类
     * @param type 对象类型
     * @param <T> 泛型
     */
    private static <T> T parse(String json, Class<T> clazz, TypeReference type) {
 
        T obj = null;
        if (!StringUtils.isEmpty(json)) {
            try {
                if (clazz != null) {
                    obj = om.readValue(json, clazz);
                } else {
                    obj = om.readValue(json, type);
                }
            } catch (IOException e) {
                log.warn(e.getMessage(), e);
                throw new IllegalArgumentException(e.getMessage());
            }
        }
        return obj;
    }
}
复制代码

结束

其实就是给大家稍微介绍下 我们的jackson,其实我之前都是用fastjson的,但是后来fastjson的漏洞太多了,总是要升级,所以我换成了jackson,我觉得吧一个项目,最好是用一个工具,而且jackson对xml的系列化也支持,并且是SpringMvc的用的工具,所以就无脑粉了。开发的那些是最近刚好再温习三国,感叹三国演义的魅力,分享给大家。我是小六六,三天打鱼,两天晒网。

猜你喜欢

转载自juejin.im/post/7016621643128635429