java:jackson 五:Custom Jackson Annotation
1 前言
参考文档地址:
https://www.baeldung.com/jackson
https://www.baeldung.com/jackson-annotations
SpringBoot自带的jackson版本如下:
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.4</version>
</parent>
或者不使用SpringBoot情况下,单独配置jackson-databind版本:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<jackson-databind.version>2.14.1</jackson-databind.version>
</properties>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
同时使用SpringBoot和自定义的jackson版本时,注意避免依赖冲突。
2 使用
@JacksonAnnotationsInside
Next let’s see how to create a custom Jackson annotation. We can make use of the @JacksonAnnotationsInside annotation
自定义jackson的注解时,如果使用了@JsonSerialize,相应的,@JsonPropertyOrder、@JsonInclude将失效,依赖自定义的序列化器等实现即可:
package com.xiaoxu.test.jackson;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.Data;
import lombok.ToString;
import java.io.IOException;
import java.lang.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Optional;
/**
* @author xiaoxu
* @date 2022-12-30
* java_demo:com.xiaoxu.test.jackson.CustomJackSonAnnotationTest
*/
public class CustomJackSonAnnotationTest {
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
/* 单独使用了@JsonSerialize(using = CusAnnoSerializer.class),可省略全局的配置 */
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(CusAnno.class, new CusAnnoSerializer());
simpleModule.addDeserializer(CusAnno.class, new CusAnnoDeSerializer());
objectMapper.registerModule(simpleModule);
}
public static void demo() throws Exception{
CusAnno cusAnno = new CusAnno();
cusAnno.setToday(new Date());
cusAnno.setTodayNew(LocalDateTime.now());
Optional.ofNullable(CusAnno.class.getAnnotation(CusJack.class)).ifPresent(annotation -> {
if(annotation.isEffect()){
System.out.println("CusJack注解生效:");
try {
System.out.println(objectMapper.writeValueAsString(cusAnno));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}else{
System.out.println("CusJack注解未生效.");
}
});
System.out.print("\n\n");
WrapCusAnno wrapCusAnno = new WrapCusAnno();
wrapCusAnno.setMid(999);
wrapCusAnno.setCusAnno(cusAnno);
System.out.println(objectMapper.writeValueAsString(wrapCusAnno));
System.out.print("\n\n");
System.out.println(objectMapper.readValue(objectMapper.writeValueAsString(cusAnno), CusAnno.class));
System.out.print("\n\n");
System.out.println(objectMapper.readValue(objectMapper.writeValueAsString(wrapCusAnno), WrapCusAnno.class));
}
public static void main(String[] args) throws Exception{
demo();
}
}
class CusAnnoSerializer extends JsonSerializer<CusAnno> implements ContextualSerializer{
@Override
public void serialize(CusAnno cusAnno, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
/* 注意:若使用writeObject()方法,不要直接把参数 cusAnno 再次写入,会造成StackOverflowError 错误*/
jsonGenerator.writeStartObject();
/* 改变自定义的顺序即可实现类似 @JsonPropertyOrder(value = {"today","todayNew","name","id"}) 的效果 */
jsonGenerator.writeStringField("name",cusAnno.getName());
jsonGenerator.writeNumberField("id",cusAnno.id+1);
Optional.ofNullable(cusAnno.getToday()).ifPresent(date -> {
try {
jsonGenerator.writeStringField("nowDay",cusAnno.getToday().toString());
} catch (IOException e) {
throw new RuntimeException("today转换异常:"+e.getMessage(),e.getCause());
}
});
Optional.ofNullable(cusAnno.getTodayNew()).ifPresent(localDate -> {
try {
jsonGenerator.writeStringField("localDate",
cusAnno.getTodayNew().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
} catch (IOException e) {
throw new RuntimeException("todayNew转换异常:"+e.getMessage(),e.getCause());
}
});
jsonGenerator.writeEndObject();
}
@Override
public JsonSerializer<CusAnno> createContextual(SerializerProvider serializerProvider,
BeanProperty beanProperty) throws JsonMappingException {
System.out.println("序列化BeanProperty:"+beanProperty);
Optional.ofNullable(beanProperty).ifPresent(beanProperty1 -> {
System.out.println("序列化BeanProperty不为null:"+beanProperty1.getAnnotation(CusJack.class));
});
return this;
}
}
class CusAnnoDeSerializer extends JsonDeserializer<CusAnno> implements ContextualDeserializer{
@Override
public CusAnno deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
int id = node.get("id").intValue();
String name = node.get("name").asText();
/* 注意:node.get("name"),若name不存在,则该值为null,可能导致NPE */
if(node.get("name").isNull()){
name = "defualt-xiaoxu";
}
String localDate = node.get("localDate").asText();
LocalDateTime dtime = LocalDateTime.parse(localDate,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
CusAnno cusAnnoDe = new CusAnno();
cusAnnoDe.setId(id);
cusAnnoDe.setName(name);
cusAnnoDe.setToday(new Date());
cusAnnoDe.setTodayNew(dtime);
return cusAnnoDe;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext,
BeanProperty beanProperty) throws JsonMappingException {
System.out.println("反序列化BeanProperty:"+beanProperty);
Optional.ofNullable(beanProperty).ifPresent(beanProperty1 -> {
System.out.println("反序列化BeanProperty不为null:"+beanProperty1.getAnnotation(CusJack.class));
});
return this;
}
}
//@CusJack 类上一定不能有该注解
@ToString
@Data
class WrapCusAnno{
int mid;
//字段上可有可无该@CusJack注解,但是类上不能有,直接带上即可
@CusJack
CusAnno cusAnno;
}
@CusJack(isEffect = true)
@Data
class CusAnno{
int id;
String name;
Date today;
LocalDateTime todayNew;
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@JacksonAnnotationsInside
/* 使用 JsonSerialize自定义的序列化器时,序列化注解@JsonPropertyOrder、
@JsonInclude将不会生效,需要自定义展示效果 */
@JsonPropertyOrder(value = {"today","todayNew","name","id"})
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonSerialize(using = CusAnnoSerializer.class)
@JsonDeserialize(using = CusAnnoDeSerializer.class)
@interface CusJack{
boolean isEffect() default false;
}
执行结果如下:
CusJack注解生效:
序列化BeanProperty:null
{
"name" : null,
"id" : 1,
"nowDay" : "Fri Dec 30 16:33:18 CST 2022",
"localDate" : "2022-12-30 16:33"
}
序列化BeanProperty:com.fasterxml.jackson.databind.BeanProperty$Std@67205a84
序列化BeanProperty不为null:@com.xiaoxu.test.jackson.CusJack(isEffect=false)
{
"mid" : 999,
"cusAnno" : {
"name" : null,
"id" : 1,
"nowDay" : "Fri Dec 30 16:33:18 CST 2022",
"localDate" : "2022-12-30 16:33"
}
}
反序列化BeanProperty:null
CusAnno(id=1, name=defualt-xiaoxu, today=Fri Dec 30 16:33:18 CST 2022, todayNew=2022-12-30T16:33)
反序列化BeanProperty:[property 'cusAnno']
反序列化BeanProperty不为null:@com.xiaoxu.test.jackson.CusJack(isEffect=false)
反序列化BeanProperty:[property 'cusAnno']
反序列化BeanProperty不为null:@com.xiaoxu.test.jackson.CusJack(isEffect=false)
WrapCusAnno(mid=999, cusAnno=CusAnno(id=1, name=defualt-xiaoxu, today=Fri Dec 30 16:33:18 CST 2022, todayNew=2022-12-30T16:33))
可见,自定义jackson注解,可以整合多个注解,使用自定义的1个注解,可达到相同效果。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/192097.html