Обзор
В предыдущей статье был представлен преобразователь ObjectMapper в Джексоне и его использование для реализации сериализации и десериализации между объектами Json и Java, и, наконец, были представлены некоторые дополнительные функции сериализации/десериализации в Джексоне. В этой статье будут представлены некоторые часто используемые аннотации (сериализация/десериализация) в Jackson и показано, как использовать эти аннотации на примерах для повышения эффективности нашей работы при обработке Json.
аннотация сериализации
@JsonAnyGetter
Аннотация @JsonAnyGetter позволяет гибко использовать поля сопоставления (пары ключ-значение, такие как Map) в качестве стандартных свойств.
Мы объявляем следующий класс Java:
@Data
@Accessors(chain = true)
public static class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
Напишите тестовый код для проверки @JsonAnyGetter:
@Test
public void testJsonAnyGetter() throws JsonProcessingException {
ExtendableBean extendableBean = new ExtendableBean();
Map<String, String> map = new HashMap<>();
map.put("age", "13");
extendableBean.setName("dxsn").setProperties(map);
log.info(new ObjectMapper().writeValueAsString(extendableBean));
//打印:{"name":"dxsn","age":"13"}
assertThat(new ObjectMapper().writeValueAsString(extendableBean)).contains("name");
assertThat(new ObjectMapper().writeValueAsString(extendableBean)).contains("age");
}
Как и выше, вы можете видеть, что пара ключ-значение (Map) в атрибуте свойств расширяется до объекта Json объекта ExtendableBean.
@JsonGetter
Аннотация @JsonGetter является заменой аннотации @JsonProperty и используется для обозначения метода как метода получения.
Мы создаем следующий класс Java
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
}
Как и выше, мы объявили в классе метод getTheName() и изменили его с помощью @JsonGetter("name"). В настоящее время этот метод будет рассматриваться Джексоном как метод получения атрибута имени.
Напишите тестовый код:
@Test
public void testJsonGetter() throws JsonProcessingException {
MyBean myBean = new MyBean(1, "dxsn");
String jsonStr = new ObjectMapper().writeValueAsString(myBean);
log.info(jsonStr);
assertThat(jsonStr).contains("id");
assertThat(jsonStr).contains("name");
}
Как видите, jackson также сериализует имя частной собственности.
@JsonPropertyOrder
Мы можем использовать аннотацию @JsonPropertyOrder, чтобы указать порядок сериализации свойств объектов Java.
@JsonPropertyOrder({"name", "id"})
//order by key's name
//@JsonPropertyOrder(alphabetic = true)
@Data
@Accessors(chain = true)
public static class MyOrderBean {
public int id;
public String name;
}
Напишите тестовый код:
@Test
public void testJsonPropertyOrder1() throws JsonProcessingException {
MyOrderBean myOrderBean = new MyOrderBean().setId(1).setName("dxsn");
String jsonStr = new ObjectMapper().writeValueAsString(myOrderBean);
log.info(jsonStr);
assertThat(jsonStr).isEqualTo("{\"name\":\"dxsn\",\"id\":1}");
}
Как и выше, вы можете видеть, что порядок свойств в сериализованном объекте Json точно такой же, как мы указали в аннотации.
@JsonRawValue
Аннотация @JsonRawValue может указать Джексону сериализовать свойство как есть.
В следующем примере мы используем @JsonRawValue для встраивания некоторого пользовательского JSON в качестве значения объекта:
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class RawBean {
public String name;
@JsonRawValue
public String json;
}
Напишите тестовый код:
@Test
public void testJsonRawValue() throws JsonProcessingException {
RawBean rawBean = new RawBean("dxsn", "{\"love\":\"true\"}");
log.info(new ObjectMapper().writeValueAsString(rawBean));
//输出:{"name":"dxsn","json":{"love":"true"}}
String result = new ObjectMapper().writeValueAsString(rawBean);
assertThat(result).contains("dxsn");
assertThat(result).contains("{\"love\":\"true\"}");
}
@JsonValue
@JsonValue означает, что Джексон будет использовать один метод для сериализации всего экземпляра.
Далее мы создаем класс enum:
@AllArgsConstructor
public static enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
@JsonValue
public String getName() {
return name;
}
}
Как и выше, мы украшаем getName() @JsonValue.
Напишите тестовый код:
@Test
public void testJsonValue() throws JsonProcessingException {
String jsonStr = new ObjectMapper().writeValueAsString(TypeEnumWithValue.TYPE2);
log.info(jsonStr);
assertThat(jsonStr).isEqualTo("Type 2");
}
Как видите, сериализованное значение объекта класса перечисления является возвращаемым значением метода getName().
@JsonRootName
Если упаковка включена, используйте аннотацию @JsonRootName, чтобы указать имя используемой корневой оболочки.
Ниже мы создаем класс Java, украшенный @JsonRootName:
@JsonRootName(value = "user")
@Data
@AllArgsConstructor
public static class UserWithRoot {
public int id;
public String name;
}
Напишите тест:
@Test
public void testJsonRootName() throws JsonProcessingException {
UserWithRoot userWithRoot = new UserWithRoot(1, "dxsn");
ObjectMapper mapper = new ObjectMapper();
//⬇️重点!!!
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
String result = mapper.writeValueAsString(userWithRoot);
log.info(result);
//输出:{"user":{"id":1,"name":"dxsn"}}
assertThat(result).contains("dxsn");
assertThat(result).contains("user");
}
В приведенном выше коде мы включаем SerializationFeature.WRAP_ROOT_VALUE ObjectMapper. Вы можете видеть, что сериализованный объект Json объекта UserWithRoot обернут в пользователя, а не просто{"id":1,"name":"dxsn"}
.
@JsonSerialize
Аннотация @JsonSerialize представляет собой пользовательский сериализатор, используемый при сериализации сущностей.
Мы определяем собственный сериализатор:
public static class CustomDateSerializer extends StdSerializer<Date> {
private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class<Date> t) {
super(t);
}
@Override
public void serialize(
Date value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
Используя собственный сериализатор, создайте класс Java:
@Data
@AllArgsConstructor
public static class Event {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
Напишите тестовый код:
@Test
public void testJsonSerialize() throws ParseException, JsonProcessingException {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
String toParse = "20-12-2014 02:30:00";
Date date = formatter.parse(toParse);
Event event = new Event("party", date);
String result = new ObjectMapper().writeValueAsString(event);
assertThat(result).contains(toParse);
}
Как видите, после декорирования указанного свойства аннотацией @JsonSerialize указанный сериализатор будет использоваться для сериализации свойства.
аннотация десериализации
@JsonCreator
Мы можем использовать аннотацию @JsonCreator для оптимизации/замены конструктора/фабрики, используемых при десериализации.
Это полезно, когда нам нужно десериализовать некоторый JSON, который не совсем соответствует целевому объекту, который нам нужно получить.
Теперь есть объект Json следующим образом:
{"id":1,"theName":"My bean"}
Мы объявляем класс Java:
@Data
public static class BeanWithCreator {
private int id;
private String name;
}
На данный момент в нашей целевой сущности нет поля theName, только поле имени. Теперь мы не хотим изменять сам объект, на этом этапе мы можем украсить конструктор с помощью аннотаций @JsonCreator и @JsonProperty:
@Data
public static class BeanWithCreator {
private int id;
private String name;
@JsonCreator
public BeanWithCreator(@JsonProperty("id") int id, @JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}
Напишите тест:
@Test
public void beanWithCreatorTest() throws JsonProcessingException {
String str = "{\"id\":1,\"theName\":\"My bean\"}";
BeanWithCreator bean = new ObjectMapper()
.readerFor(BeanWithCreator.class)
.readValue(str);
assertThat(bean.getId()).isEqualTo(1);
assertThat(bean.getName()).isEqualTo("My bean");
}
Видно, что хотя имена полей в объекте Json отличаются от названий в классе сущностей, десериализация прошла успешно, поскольку мы вручную указали имена сопоставленных полей.
@JacksonInject
@JacksonInject означает, что свойства в java-объекте будут назначаться путем инъекции, а не получать их значение из данных JSON.
Создайте следующий класс сущности с полями, измененными @JacksonInject:
public static class BeanWithInject {
@JacksonInject
public int id;
public String name;
}
Напишите тест:
@Test
public void jacksonInjectTest() throws JsonProcessingException {
String json = "{\"name\":\"dxsn\"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);
BeanWithInject bean = new ObjectMapper().reader(inject)
.forType(BeanWithInject.class)
.readValue(json);
assertThat(bean.id).isEqualTo(1);
assertThat(bean.name).isEqualTo("dxsn");
}
Как и выше, мы десериализуем строку json (существует только поле имени) в тесте, где идентификатор присваивается свойству путем инъекции.
@JsonAnySetter
@JsonAnySetter позволяет нам гибко использовать карты (пары ключ-значение, карта) в качестве стандартных свойств. При десериализации свойства JSON будут добавлены на карту.
Создайте класс сущности с помощью @JsonAnySetter:
public static class ExtendableBean {
public String name;
public Map<String, String> properties;
@JsonAnySetter
public void add(String key, String value) {
if (properties == null) {
properties = new HashMap<>();
}
properties.put(key, value);
}
}
Напишите тест:
@Test
public void testJsonAnySetter() throws JsonProcessingException {
String json = "{\"name\":\"dxsn\", \"attr2\":\"val2\", \"attr1\":\"val1\"}";
ExtendableBean extendableBean = new ObjectMapper().readerFor(ExtendableBean.class).readValue(json);
assertThat(extendableBean.name).isEqualTo("dxsn");
assertThat(extendableBean.properties.size()).isEqualTo(2);
}
Видно, что атрибуты attr1 и attr2 в объекте json входят в свойства после десериализации.
@JsonSetter
@JsonSetter — это альтернатива @JsonProperty, которая помечает метод как метод установки свойства. Это полезно, когда нам нужно прочитать некоторые данные JSON, но целевой класс сущности не совсем соответствует этим данным, поэтому нам нужно оптимизировать, чтобы соответствовать этим данным.
Создайте следующий класс сущности:
@Data
public static class MyBean {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = "hello " + name;
}
}
Напишите тест:
@Test
public void testJsonSetter() throws JsonProcessingException {
String json = "{\"id\":1,\"name\":\"dxsn\"}";
MyBean bean = new ObjectMapper().readerFor(MyBean.class).readValue(json);
assertThat(bean.getName()).isEqualTo("hello dxsn");
}
Видно, что атрибут name в объекте json — «dxsn». Мы определяем метод, модифицированный аннотацией @JsonSetter("name") в классе MyBean, которая указывает, что при десериализации объекта этого класса Свойства имени будут получены из этого метода. Наконец, значение name в объекте MyBean становится hello dxsn.
@JsonDeserialize
Аннотация @JsonDeserialize указывает десериализатор, который следует использовать при десериализации.
Далее определяется пользовательский десериализатор:
public static class CustomDateDeserializer extends StdDeserializer<Date> {
private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Date deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException {
String date = jsonparser.getText();
try {
return formatter.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
Создайте класс сущности, украшенный @JsonDeserialize (используя = CustomDateDeserializer.class):
public static class Event {
public String name;
@JsonDeserialize(using = CustomDateDeserializer.class)
public Date eventDate;
}
Напишите тест:
@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
throws IOException {
String json = "{\"name\":\"party\",\"eventDate\":\"20-12-2014 02:30:00\"}";
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Event event = new ObjectMapper().readerFor(Event.class).readValue(json);
assertThat(event.name).isEqualTo("party");
assertThat(event.eventDate).isEqualTo(df.format(event.eventDate));
}
Видно, что в объекте Event свойство eventDate десериализует «20-12-2014 02:30:00» в объект Date с помощью пользовательского десериализатора.
@JsonAlias
@JsonAlias Определяет одно или несколько альтернативных имен свойств во время десериализации. Давайте посмотрим, как эта аннотация работает на простом примере:
@Data
public static class AliasBean {
@JsonAlias({"fName", "f_name"})
private String firstName;
private String lastName;
}
Как и выше, мы написали класс сущности AliasBean, украшенный @JsonAlias.
Напишите тест:
@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
assertThat(aliasBean.getFirstName()).isEqualTo("John");
}
Видно, что хотя имя поля в json-объекте — fName, свойство firstName изменено с помощью @JsonAlias в AliasBean, и указаны два псевдонима. Таким образом, после десериализации fName сопоставляется со свойством firstName объекта AliasBean.
Более
В дополнение к приведенным выше аннотациям Джексон также предоставляет множество дополнительных аннотаций, которые здесь не перечислены.
- @JsonProperty: вы можете добавить аннотацию @JsonProperty к указанному свойству класса, чтобы указать соответствующее имя свойства в JSON.
- @JsonFormat: Эта аннотация может указывать вывод строки в формате при сериализации атрибута типа даты/времени в объекте, например: @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = «dd-MM-yyyy hh:mm:ss») .
- @JsonUnwrapped: @JsonUnwrapped определяет значение, которое должно быть сведено к минимуму при сериализации/десериализации.
- @JsonIgnore: игнорировать измененные свойства при сериализации/десериализации.
- ......
Суммировать
В этой статье в основном представлены аннотации сериализации/десериализации, обычно используемые Джексоном, и, наконец, представлено несколько часто используемых общих аннотаций. Аннотации, предоставленные в Джексоне, удаляют многое, многое другое, перечисленное в этой статье.Использование аннотаций может упростить нашу работу по сериализации/десериализации. Если вы хотите заменить библиотеку на Jackson, я надеюсь, что эта статья поможет вам.
Кодовый адрес, указанный в этой статье:git ee.com/количество guest8chen/…
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
Добро пожаловать в блог автора:blog.dongxishaonian.tech
Подписывайтесь на официальный аккаунт автора и публикуйте различные оригинальные/качественные технические статьи ⬇️