Maison > Java > JavaBase > le corps du texte

L'analyseur Java JSON que je considère comme le plus génial : Jackson

coldplay.xixi
Libérer: 2020-12-16 09:48:54
avant
2501 Les gens l'ont consulté

Tutoriel de base JavaLa colonne présente l'analyseur Java JSON

L'analyseur Java JSON que je considère comme le plus génial : Jackson

Recommandé (Gratuit) : Tutoriel de base Java

Dans le monde de la programmation d'aujourd'hui, JSON est devenu le protocole préféré pour transmettre des informations du client au serveur. Il n'est pas exagéré de dire que XML est l'ancienne vague photographiée morte sur la plage.

Malheureusement, le JDK ne possède pas de bibliothèque JSON, je ne sais pas pourquoi ne pas en faire. A l’époque de Log4j, java.util.logging a également été lancé pour rivaliser, même si au final peu de gens l’ont utilisé.

La raison pour laquelle Java est génial est que son écosystème est très complet. JDK n'a pas de bibliothèque JSON, mais il existe des bibliothèques tierces, qui sont plutôt bonnes. Par exemple, les pieds de cochon dans cet article. - Jackson, GitHub star 6.1k, analyseur JSON par défaut de Spring Boot.

Comment prouver cela ?

Lorsque nous créons un nouveau projet Web Spring Boot via Starter, nous pouvons voir Jackson dans les dépendances Maven.

Lanalyseur Java JSON que je considère comme le plus génial : Jackson

Jackson présente de nombreux avantages :

  • Il est plus rapide d'analyser des fichiers volumineux
  • il prend moins de mémoire lors de son exécution ; , de meilleures performances ;
  • L'API est très flexible et facile à étendre et à personnaliser.

Le module principal de Jackson se compose de trois parties :

  • jackson-core, le package principal, fournit des API associées basées sur l'analyse en « mode flux », notamment JsonPaser et JsonGenerator.
  • jackson-annotations, un package d'annotations, fournit des fonctions d'annotation standard ;
  • jackson-databind, un package de liaison de données, fournit des API associées (ObjectMapper) basées sur l'analyse de « liaison d'objet » et l'API associée. (JsonNode) pour l'analyse du "modèle d'arbre".

01. Introduire la dépendance Jackson

Pour utiliser Jackson, vous devez ajouter la dépendance Jackson dans le fichier pom.xml.

<dependency>
    <groupid>com.fasterxml.jackson.core</groupid>
    <artifactid>jackson-databind</artifactid>
    <version>2.10.1</version>
</dependency>
Copier après la connexion

jackson-databind dépend de jackson-core et jackson-annotations, donc après avoir ajouté jackson-databind, Maven introduira automatiquement jackson-core et jackson-annotations dans le projet.

Lanalyseur Java JSON que je considère comme le plus génial : Jackson

La raison pour laquelle Maven est si adorable est qu'il peut secrètement nous aider à faire ce que nous devons faire.

02. Utiliser ObjectMapper

L'API la plus couramment utilisée de Jackson est ObjectMapper basée sur la « liaison d'objet », qui sérialise les objets Java en JSON via une série de méthodes writeValue et peut être stockée dans différents formats. .

  • writeValueAsString(Object value) méthode, stocke l'objet sous forme de chaîne
  • writeValueAsBytes(Object value) méthode, stocke l'objet sous forme de tableau d'octets
  • writeValue(File resultFile, Object value) méthode, stocke l'objet sous forme de tableau d'octets Les objets sont stockés sous forme de fichiers

Jetons un coup d'œil à l'exemple de code de stockage d'objets sous forme de chaînes :

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 微信搜索「沉默王二」,回复 Java
 *
 * @author 沉默王二
 * @date 2020/11/26
 */
public class Demo {
    public static void main(String[] args) throws JsonProcessingException {
        Writer wanger = new Writer("沉默王二", 18);
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(wanger);
        System.out.println(jsonString);
    }
}

class Writer {
    private String name;
    private int age;

    public Writer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
Copier après la connexion

La sortie du programme est la suivante :

{
  "name" : "沉默王二",
  "age" : 18
}
Copier après la connexion

Tous les champs ne le sont pas. Pour prendre en charge la sérialisation et la désérialisation, les règles suivantes doivent être respectées :

  • Si le modificateur du champ est public, le champ peut être sérialisé et désérialisé (pas une manière standard d’écrire).
  • Si le modificateur d'un champ n'est pas public, mais que ses méthodes getter et setter sont publiques, le champ est sérialisable et désérialisable. La méthode getter est utilisée pour la sérialisation et la méthode setter est utilisée pour la désérialisation.
  • Si un champ n'a qu'une méthode de définition publique mais pas de méthode de lecture publique, le champ ne peut être utilisé que pour la désérialisation.

Si vous souhaitez modifier les règles de sérialisation et de désérialisation par défaut, vous devez appeler la méthode setVisibility() d'ObjectMapper. Sinon, une InvalidDefinitionException sera levée.

ObjectMapper désérialise JSON en objets Java provenant de différentes sources de données via la série de méthodes readValue. Méthode

  • readValue(String content, Class<t> valueType)</t>, désérialise une chaîne en un objet Java Méthode
  • readValue(byte[] src, Class<t> valueType)</t>, désérialise un tableau d'octets en un objet Java
  • readValue(File src, Class<t> valueType)</t> méthode , désérialisez des fichiers en objets Java

Jetons un coup d'œil à l'exemple de code de désérialisation de chaînes en objets Java :

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 微信搜索「沉默王二」,回复 Java
 *
 * @author 沉默王二
 * @date 2020/11/26
 */
public class Demo {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = "{\n" +
                "  \"name\" : \"沉默王二\",\n" +
                "  \"age\" : 18\n" +
                "}";
        Writer deserializedWriter = mapper.readValue(jsonString, Writer.class);
        System.out.println(deserializedWriter);
    }
}

class Writer{
    private String name;
    private int age;

    // getter/setter

    @Override
    public String toString() {
        return "Writer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Copier après la connexion

La sortie du programme est la suivante Affichage :

Writer{name='沉默王二', age=18}
Copier après la connexion

PS : Si l'objet désérialisé a un constructeur avec des paramètres, il doit avoir un constructeur par défaut vide, sinon la ligne InvalidDefinitionException sera lancée.

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.itwanger.jackson.Writer` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{
  "name" : "沉默王二",
  "age" : 18
}"; line: 2, column: 3]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1589)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1055)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
    at com.itwanger.jackson.Demo.main(Demo.java:19)
Copier après la connexion

L'API la plus couramment utilisée de Jackson est ObjectMapper basée sur la « liaison d'objet ».

ObjectMapper peut également analyser JSON en objets JsonNode basés sur un « modèle d'arbre ».

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 微信搜索「沉默王二」,回复 Java
 *
 * @author 沉默王二
 * @date 2020/11/26
 */
public class JsonNodeDemo {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        String json = "{ \"name\" : \"沉默王二\", \"age\" : 18 }";
        JsonNode jsonNode = mapper.readTree(json);
        String name = jsonNode.get("name").asText();
        System.out.println(name); // 沉默王二
    }
}
Copier après la connexion

借助 TypeReference 可以将 JSON 字符串数组转成泛型 List,来看下面的示例:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

/**
 * 微信搜索「沉默王二」,回复 Java
 *
 * @author 沉默王二
 * @date 2020/11/26
 */
public class TypeReferenceDemo {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        String json = "[{ \"name\" : \"沉默王三\", \"age\" : 18 }, { \"name\" : \"沉默王二\", \"age\" : 19 }]";
        List<author> listAuthor = mapper.readValue(json, new TypeReference<list>>(){});
        System.out.println(listAuthor);
    }
}
class Author{
    private String name;
    private int age;

    // getter/setter

    // toString
}</list></author>
Copier après la connexion

03、更高级的配置

Jackson 之所以牛掰的一个很重要的因素是可以实现高度灵活的自定义配置。

在实际的应用场景中,JSON 中常常会有一些 Java 对象中没有的字段,这时候,如果直接解析的话,会抛出 UnrecognizedPropertyException 异常。

下面是一串 JSON 字符串:

String jsonString = "{\n" +
                "  \"name\" : \"沉默王二\",\n" +
                "  \"age\" : 18\n" +
                "  \"sex\" : \"男\",\n" +
                "}";
Copier après la connexion

但 Java 对象 Writer 中没有定义 sex 字段:

class Writer{
    private String name;
    private int age;

    // getter/setter
}
Copier après la connexion

我们来尝试解析一下:

ObjectMapper mapper = new ObjectMapper();
Writer deserializedWriter = mapper.readValue(jsonString, Writer.class);
Copier après la connexion

不出意外,抛出异常了,sex 无法识别。

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "sex" (class com.itwanger.jackson.Writer), not marked as ignorable (2 known properties: "name", "age"])
 at [Source: (String)"{
  "name" : "沉默王二",
  "age" : 18,
  "sex" : "男"
}"; line: 4, column: 12] (through reference chain: com.itwanger.jackson.Writer["sex"])
Copier après la connexion

怎么办呢?可以通过 configure() 方法忽略掉这些“无法识别”的字段。

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Copier après la connexion

除此之外,还有其他一些有用的配置信息,来了解一下:

// 在序列化时忽略值为 null 的属性
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 忽略值为默认值的属性
mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
Copier après la connexion

04、处理日期格式

对于日期类型的字段,比如说 java.util.Date,如果不指定格式,序列化后将显示为 long 类型的数据,这种默认格式的可读性很差。

{
  "age" : 18,
  "birthday" : 1606358621209
}
Copier après la connexion

怎么办呢?

第一种方案,在 getter 上使用 @JsonFormat 注解。

private Date birthday;

// GMT+8 是指格林尼治的标准时间,在加上八个小时表示你现在所在时区的时间
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
public Date getBirthday() {
    return birthday;
}

public void setBirthday(Date birthday) {
    this.birthday = birthday;
}
Copier après la connexion

再来看一下结果:

{
  "age" : 18,
  "birthday" : "2020-11-26 03:02:30"
}
Copier après la connexion

具体代码如下所示:

ObjectMapper mapper = new ObjectMapper();
Writer wanger = new Writer("沉默王二", 18);
wanger.setBirthday(new Date());
String jsonString = mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(wanger);
System.out.println(jsonString);
Copier après la connexion

第二种方案,调用 ObjectMapper 的 setDateFormat() 方法。

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(StdDateFormat.getDateTimeInstance());
Writer wanger = new Writer("沉默王二", 18);
wanger.setBirthday(new Date());
String jsonString = mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(wanger);
System.out.println(jsonString);
Copier après la connexion

输出结果如下所示:

{
  "name" : "沉默王二",
  "age" : 18,
  "birthday" : "2020年11月26日 上午11:09:51"
}
Copier après la connexion

05、字段过滤

在将 Java 对象序列化为 JSON 时,可能有些字段需要过滤,不显示在 JSON 中,Jackson 有一种比较简单的实现方式。

@JsonIgnore 用于过滤单个字段。

@JsonIgnore
public String getName() {
    return name;
}
Copier après la connexion

@JsonIgnoreProperties 用于过滤多个字段。

@JsonIgnoreProperties(value = { "age","birthday" })
class Writer{
    private String name;
    private int age;
    private Date birthday;
}
Copier après la connexion

06、自定义序列化和反序列化

当 Jackson 默认序列化和反序列化不能满足实际的开发需要时,可以自定义新的序列化和反序列化类。

自定义的序列化类需要继承 StdSerializer,同时重写 serialize() 方法,利用 JsonGenerator 生成 JSON,示例如下:

/**
 * 微信搜索「沉默王二」,回复 Java
 *
 * @author 沉默王二
 * @date 2020/11/26
 */
public class CustomSerializer extends StdSerializer<man> {
    protected CustomSerializer(Class<man> t) {
        super(t);
    }

    public CustomSerializer() {
        this(null);
    }

    @Override
    public void serialize(Man value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("name", value.getName());
        gen.writeEndObject();
    }
}

class Man{
    private int age;
    private String name;

    public Man(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}</man></man>
Copier après la connexion

定义好自定义序列化类后,要想在程序中调用它们,需要将其注册到 ObjectMapper 的 Module 中,示例如下所示:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
        new SimpleModule("CustomSerializer", new Version(1, 0, 0, null, null, null));
module.addSerializer(Man.class, new CustomSerializer());
mapper.registerModule(module);
Man man = new Man( 18,"沉默王二");
String json = mapper.writeValueAsString(man);
System.out.println(json);
Copier après la connexion

程序输出结果如下所示:

{"name":"沉默王二"}
Copier après la connexion

自定义序列化类 CustomSerializer 中没有添加 age 字段,所以只输出了 name 字段。

再来看一下自定义的反序列化类,继承 StdDeserializer,同时重写 deserialize() 方法,利用 JsonGenerator 读取 JSON,示例如下:

public class CustomDeserializer extends StdDeserializer<woman> {
    protected CustomDeserializer(Class> vc) {
        super(vc);
    }

    public CustomDeserializer() {
        this(null);
    }

    @Override
    public Woman deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = p.getCodec().readTree(p);
        Woman woman = new Woman();
        int age = (Integer) ((IntNode) node.get("age")).numberValue();
        String name = node.get("name").asText();
        woman.setAge(age);
        woman.setName(name);
        return woman;
    }
}
class Woman{
    private int age;
    private String name;

    public Woman() {
    }

    // getter/setter

    @Override
    public String toString() {
        return "Woman{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}</woman>
Copier après la connexion

通过 JsonNode 把 JSON 读取到一个树形结构中,然后通过 JsonNode 的 get 方法将对应字段读取出来,然后生成新的 Java 对象,并返回。

定义好自定义反序列化类后,要想在程序中调用它们,同样需要将其注册到 ObjectMapper 的 Module 中,示例如下所示:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
        new SimpleModule("CustomDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Woman.class, new CustomDeserializer());
mapper.registerModule(module);
String json = "{ \"name\" : \"三妹\", \"age\" : 18 }";
Woman woman = mapper.readValue(json, Woman.class);
System.out.println(woman);
Copier après la connexion

程序输出结果如下所示:

Woman{age=18, name='三妹'}
Copier après la connexion

07、结语

哎呀,好像不错哦,Jackson 绝对配得上“最牛掰”这三个字,虽然有点虚。如果只想简单的序列化和反序列化,使用 ObjectMapper 的 write 和 read 方法即可。

如果还想更进一步的话,就需要对 ObjectMapper 进行一些自定义配置,或者加一些注解,以及直接自定义序列化和反序列化类,更贴近一些 Java 对象。

需要注意的是,对日期格式的字段要多加小心,尽量不要使用默认配置,可读性很差。

好了,通过这篇文章的系统化介绍,相信你已经完全摸透 Jackson 了,我们下篇文章见。

PS:如果你恰好需要一份 Java 精进路线的话,我这里有一份,我差不多花了 3 天的时间整理的,还挺受欢迎的,已经 2000 多赞了,每个阶段都很详细。

相关免费学习推荐:php编程(视频)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal