Исходная ссылка: http://www.dubby.cn/detail.html?id=9070
Первые несколько статей, которые представили Джексона (О Джексоне,ядро Джексона), хотя это очень хорошо, но я верю, что вы готовы использовать его в проекте, потому что он очень сложен в использовании, возможно, это причина, по которой многие люди хотят использовать Fastjson. Почему это кажется таким сложным, потому что jackson-core предоставляет очень низкоуровневый API, мы можем полностью понять детали, но цена сложнее в эксплуатации.
В этой статье рассказывается об использовании высокоуровневых API, чтобы вы могли увидеть, насколько простым и легким может быть Джексон.
Зависимости Maven
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
Поскольку jackson-databind зависит от ядра и аннотаций, здесь необходимо полагаться на эти три jar-файла.
Преобразование между POJO и JSON
Учитывая достаточно простой POJO:
public class MyValue {
public String name;
public int age;
}
Примечание: Если вы используете геттеры/сеттеры, вы можете использовать private/protected для изменения свойств.Если вы используете public напрямую, вам не нужны геттеры/сеттеры.
использоватьdatabind
, нам нужен самый простой объектcom.fasterxml.jackson.databind.ObjectMapper
, здесь мы строим:
ObjectMapper mapper = new ObjectMapper();
Примечание. Этот преобразователь можно использовать повторно, как и HttpClient.
Простое использование десериализации JSON в объект выглядит следующим образом:
MyValue value = mapper.readValue(new File("data.json"), MyValue.class);
// or:
value = mapper.readValue(new URL("http://www.dubby.cn/api/entry.json"), MyValue.class);
// or:
value = mapper.readValue("{\"name\":\"Bob\", \"age\":13}", MyValue.class);
Простое использование сериализации объекта в JSON выглядит следующим образом:
mapper.writeValue(new File("result.json"), myResultObject);
// or:
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// or:
String jsonString = mapper.writeValueAsString(myResultObject);
На самом деле, этого шага достаточно для многих читателей. Потому что это то, чего мы хотим большую часть времени. Но продолжайте читать, есть еще несколько, которые вы могли бы использовать.
набор, дерево
Если вы не используете простой POJO, ноList
,Map
:
Map<String, Integer> scoreByName = mapper.readValue(jsonSource, Map.class);
List<String> names = mapper.readValue(jsonSource, List.class);
mapper.writeValue(new File("names.json"), names);
Если ваша десериализация более сложная, вы можете указать тип:
Map<String, ResultValue> results = mapper.readValue(jsonSource, new TypeReference<Map<String, ResultValue>>() { } );
Подумайте: зачем вам указывать тип? (введите стирание)
Примечание. Не нужно указывать при сериализации, только при десериализации.
Хотя это кажется очень удобным, иногда возникают очень неприятные ситуации, вы можете рассмотреть возможность использования этого времени.модель дерева:
//如果结果可能是Object或者是Array,那可以使用JsonNode;
//如果你知道是Object,你可以直接强转成ObjectNode;如果你知道是Array,你可以直接强转成ArrayNode;
ObjectNode root = (ObjectNode) mapper.readTree("stuff.json");
String name = root.get("name").asText();
int age = root.get("age").asInt();
// 还可以修改这个树,然后再输出成json字符串
root.with("other").put("type", "student");
String json = mapper.writeValueAsString(root);
// with above, we end up with something like as 'json' String:
// {
// "name" : "Bob", "age" : 13,
// "other" : {
// "type" : "student"
// }
// }
JSON в приведенном выше примере выглядит следующим образом:
{
"name" : "Bob", "age" : 13,
"other" : {
"type" : "student"
}
}
Если тип json слишком динамичен для десериализации в объект, древовидная модель подходит больше, чем привязка данных.
Потоковый парсер, генератор
Прочитав приведенное выше введение, я думаю, вы должны быть вполне удовлетвореныObjectMapper
Но если вы хотите контролировать некоторые из основных деталей или иметь более высокие требования к производительности, вы можете передатьObjectMapper
устанавливать. Я предлагаю вам взглянутьядро Джексона:
JsonFactory f = mapper.getFactory();
// 1、输入JSON字符串
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
JsonGenerator g = f.createGenerator(outputStream);
// 输出JSON: { "message" : "Hello world!" }
g.writeStartObject();
g.writeStringField("message", "Hello world!");
g.writeEndObject();
g.close();
// 2、把JSON字符串反序列化
JsonParser p = f.createParser(outputStream.toString());
JsonToken t = p.nextToken(); // Should be JsonToken.START_OBJECT
t = p.nextToken(); // JsonToken.FIELD_NAME
if ((t != JsonToken.FIELD_NAME) || !"message".equals(p.getCurrentName())) {
// handle error
}
t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
// similarly
}
String msg = p.getText();
System.out.printf("My message to you is: %s!\n", msg);
p.close();
Вы также можете построить непосредственно
JsonFactory
, который затем передается как параметр конструктора вObjectMapper
.
настроить
Есть два аспекта конфигурации,характеристикаианнотация.
Конфигурация функций
Чтобы привести простой пример использования конфигурации функции, сначала дайте конфигурацию сериализации:
// 设置序列化成漂亮的JSON,而不是压缩的字符串
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// 如果你要序列化的对象没有字段(很搞笑吧),会抛异常,可以设置这个来避免异常,直接序列化成`{}`
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 默认Date会序列化成时间戳,可以设置这个来序列化成`date":"2017-12-09T12:50:13.000+0000`这个样子
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Пример конфигурации десериализации:
// 默认,如果反序列化时,JSON字符串里有字段,而POJO中没有定义,会抛异常,可以设置这个来忽略未定义的字段
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 默认如果是字符串(""),反序列化会失败,可以开启这个设置,字符串("")会被反序列化成(null)
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
Кроме того, вы также можете указать некоторые конфигурации для низкоуровневых деталей сериализации и десериализации, сначала укажите конфигурацию синтаксического анализа:
// 默认如果JSON中有C/C++风格的注释,在反序列化的时候会报错,可以指定这个配置来忽略C/C++风格的注释
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
//默认JSON字符串如果字段名没有用双引号包裹,回报错,可以设置这个来支持这种非正规的JSON(JS支持这种非正规的JSON)
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 默认如果JSON中是用的单引号包裹字段和值,反序列化时会报错,可以设置这个来兼容单引号这种非正规的JSON
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
Затем дайте конфигурацию генерации:
// 把非ASCII转义成ASCII值,如(杨正)会被转义成(\u6768\u6B63)
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
Конфигурация аннотации
изменить имя поля
аннотация@JsonProperty
:
public class MyBean {
private String _name;
// 默认是`theName`,现在改为`name`
@JsonProperty("name")
public String getTheName() { return _name; }
// 只需要修饰getter或者setter其中的一个就可以了,这里可以省略不写
public void setTheName(String n) { _name = n; }
}
игнорировать поля
@JsonIgnore
Отдельные поля можно игнорировать,@JsonIgnoreProperties
Можно добавить в определение класса:
// 序列化和反序列化时,直接忽略JSON中的foo和bar字段
@JsonIgnoreProperties({ "foo", "bar" })
public class MyBean
{
// 序列化和反序列化时,直接忽略JSON中的internal字段
@JsonIgnore
public String internal;
// 正常字段
public String external;
@JsonIgnore
public void setCode(int c) { _code = c; }
// 虽然这里没有修饰,但是setter被修饰了,所以也会被忽略
public int getCode() { return _code; }
}
Из приведенного выше мы видим, что аннотация одинакова для имени поля, сеттера и геттера, и изменение любого из них приведет к прямому игнорированию поля, но мы можем игнорировать десериализацию по значению, но не сериализацию, или наоборот:
public class ReadButDontWriteProps {
private String _name;
@JsonProperty public void setName(String n) { _name = n; }
@JsonIgnore public String getName() { return _name; }
}
использовать здесь@JsonProperty
Гарантируется, что хотя при сериализации имя будет игнорироваться, это поле можно нормально получить при десериализации из JSON.
пользовательский конструктор
В отличие от других инструментов привязки данных, Джексон не требует, чтобы ваш POJO имел конструктор по умолчанию (конструктор без аргументов). Вы можете указать конструктор для получения десериализованного значения поля:
public class CtorBean
{
public final String name;
public final int age;
@JsonCreator
private CtorBean(@JsonProperty("name") String name,
@JsonProperty("age") int age)
{
this.name = name;
this.age = age;
}
}
Конструкторы могут быть публичными, приватными или любыми другими модификаторами.
Для некоторых неизменяемых объектов это может быть полезно, кроме конструкторов,@JsonCreator
Эта аннотация также может определять фабричный метод:
public class FactoryBean
{
// fields etc omitted for brewity
@JsonCreator
public static FactoryBean create(@JsonProperty("name") String name) {
// construct and return an instance
}
}
Примечание: конструктор (@JsonCreator
и@JsonProperty
) и сеттеры не исключают друг друга, их можно смешивать.
заполнить, преобразовать
У Джексона также есть интересная особенность, о которой мало кто знает. Это преобразование между POJO и POJO. Концептуально это можно понимать как POJO1->JSON->POJO2, но на самом деле средний шаг будет опущен, и JSON фактически не будет генерироваться, а будут использоваться другие более эффективные реализации:
ResultType result = mapper.convertValue(sourceObject, ResultType.class);
Есть и другие варианты использования:
// List<Integer> -> int[]
List<Integer> sourceList = ...;
int[] ints = mapper.convertValue(sourceList, int[].class);
// POJO -> Map
Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class);
// Map -> POJO
PojoType pojo = mapper.convertValue(propertyMap, PojoType.class);
// decode Base64! (default byte[] representation is base64-encoded String)
Можно даже декодировать коды base64:
//解码
String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";
byte[] binary = mapper.convertValue(base64, byte[].class);
System.out.println(new String(binary));
//编码
String str = "Man is distinguished, not only by his reason, but by this";
String base = mapper.convertValue(str.getBytes(), String.class);
System.out.println(base);
Таким образом, Jackson даже достаточно мощен, чтобы заменить компоненты Apache Commons.