当前位置: 首页 > news >正文

一文了解Jackson注解@JsonFormat及失效解决

背景

项目中使用WRITE_DATES_AS_TIMESTAMPS: true转换日期格式为时间戳未生效。如下:

spring:
  jackson:
    time-zone: Asia/Shanghai
    serialization:
      WRITE_DATES_AS_TIMESTAMPS: true

尝试是否关于时间的注解是否会生效,使用@JsonForma@JsonFiled均失效。

常见失效原因及解决方法

@JsonFormat是用于指定Java对象序列化为JSON字符串时的格式化方式的注解。如果@JsonFormat失效,可能是以下原因:

  1. 未正确导入Jackson库
  2. 注解位置不正确
  3. 注解参数设置错误

解决方法:

  1. 确认是否正确导入了Jackson库,可以在pom.xml文件中添加以下依赖:
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

2、确认注解位置是否正确,例如:

public class User {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
    // ...
}

3、确认注解参数是否正确设置,例如:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
public Date getCreatedDate() {
    return createdDate;
}

以上是常见的解决方法,如果还有问题可以提供更具体的错误信息进行排查。

本次问题解决

失效原因

因为项目中使用了Gson替换Jackson。
代码如下:

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import springfox.documentation.spring.web.json.Json;

import java.lang.reflect.Type;

public class JsonToGson implements JsonSerializer<Json> {
    @Override
    public JsonElement serialize(Json json, Type type, JsonSerializationContext context) {
        return JsonParser.parseString(json.value());
    }
}
@Configuration
public class SwaggerWebConfiguration implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(httpMessageConverter -> httpMessageConverter instanceof MappingJackson2HttpMessageConverter);
        converters.add(gsonHttpMessageConverters());
    }

    @Bean
    public GsonHttpMessageConverter gsonHttpMessageConverters() {
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter())
                .create();
        GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter(gson);
        return gsonConverter;
    }
}

解决方案一:去掉Gson转换即可。

解决方案二:重新添加MappingJackson2HttpMessageConverter的bean

@Autowired(required = false)
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;


@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
    if (Objects.isNull(mappingJackson2HttpMessageConverter)) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
    } else {
        converters.add(0, mappingJackson2HttpMessageConverter);
    }

}

@Autowired(required = false)
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
    if (Objects.isNull(mappingJackson2HttpMessageConverter)) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
    } else {
        converters.add(0, mappingJackson2HttpMessageConverter);
    }
}

解析

Jackson一直是springframework默认的json库,从4.1开始,springframework支持通过配置GsonHttpMessageConverter的方式使用Gson。

Spring MVC中,一旦请求退出@Controller,它将寻找一个视图来呈现。当指定了@RequestBody@RestController时,我们会告诉Spring跳过这一步,将java对象通过model写入响应结果。Spring通过HttpMessageConverter来执行Java对象向其它类型(通常是Json)的转换,Spring默认使用的是 MappingJackson2HttpMessageConverter,所以如果希望使用Gson来执行这种转换,可用使用GsonHttpMessageConverter替换Jackson

小拓展

在Spring Boot提供了与三个JSON映射库的集成:Gson、默认库 Jackson 、JSON-B

@JsonFormat与@JSONField简介

@JsonFormat

@JsonFormat是Java中的一个Jackson注解,用于指定某个字段或属性,或整个类的JSON序列化或反序列化格式。它允许在将数据类型转换为或从JSON格式转换时自定义日期、数字、布尔值等数据类型的格式。

例如,如果您有一个Java类,其中包含一个Date字段,您希望以特定格式将其序列化为JSON,您可以使用@JsonFormat注解来指定该格式:

示例如下:Jackson在序列化或反序列化myDate字段时使用“yyyy-MM-dd”格式。

public class MyClass {
  @JsonFormat(pattern="yyyy-MM-dd")
  private Date myDate;
  // ...
}

@JSONField

@JSONField是阿里巴巴的fastjson库中的一个注解,用于指定Java对象属性在序列化为JSON字符串时的名称、顺序、格式等信息。例如,可以使用@JSONField(name=“username”)指定Java对象属性在序列化为JSON字符串时使用"username"作为属性名。

区别

@JsonFormat和@JSONField都是用于控制Java对象属性在序列化为JSON字符串时的格式,但是它们有一些不同之处。

@JsonFormat是Jackson库中的一个注解,用于指定Java对象属性在序列化为JSON字符串时的日期、时间、数字等格式。例如,可以使用@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”)指定Java对象属性在序列化为JSON字符串时使用指定的日期时间格式。

@JSONField是阿里巴巴的fastjson库中的一个注解,用于指定Java对象属性在序列化为JSON字符串时的名称、顺序、格式等信息。例如,可以使用@JSONField(name=“username”)指定Java对象属性在序列化为JSON字符串时使用"username"作为属性名。

因此,虽然@JsonFormat和@JSONField都可以用于控制Java对象属性在序列化为JSON字符串时的格式,但是它们的作用范围和使用方式略有不同。

jackson自定义日期注解

依赖HttpMessageConverter默认实现如下:

jackson:MappingJackson2HttpMessageConverter;

请添加图片描述

gson:GsonHttpMessageConverter;

请添加图片描述

fastjson : FastJsonHttpMessageConverter

1、自定义转换类:

public class DateToJsonSerializer extends JsonSerializer<Date> implements ContextualSerializer {

    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public DateToJsonSerializer() {
    }

    @Override
    public void serialize(Date arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
        if (null != arg0) {
            arg1.writeString(this.df.format(arg0));
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)   {
        AnnotationMap annotated = property.getMember().getAllAnnotations();

        JsonFormat jsonFormat = annotated.get(JsonFormat.class);
        if (jsonFormat != null && jsonFormat.pattern() != null){
            df = new SimpleDateFormat(jsonFormat.pattern());
        }
        return this;
    }
}

2、使用

public class MyClass {
  @JsonSerialize(using = DateToJsonSerializer .class)
  private Date myDate;
  // ...
}

在这里插入图片描述

翩若惊鸿,婉若游龙。

相关文章:

  • 全自动托盘四向穿梭车|拥有输送系统提升机AGV的托盘四向穿梭车立体库的软硬件配置系统
  • “你要多弄弄算法”
  • 【Android -- 开发工具】Xshell 6 安装和使用教程
  • Tomcat And Servlet (1)
  • C++ 学习笔记(十)(继承、抽象篇)
  • 【蓝桥杯集训·每日一题】 AcWing 3996. 涂色
  • 【Linux】基础IO(一) :文件描述符,文件流指针,重定向
  • 网络安全文章汇总导航(持续更新)
  • 菜鸟刷题Day1
  • C语言通讯录应用程序:从设计到实现
  • python常见算法(chatgpt算法实现)
  • C++类和对象(上篇)
  • 东北大学最优化知识点总结
  • 投稿指南【NO.8】计算机学会CCF推荐期刊和会议分享(计算机体系结构/并行与分布计算/存储系统)
  • 【JavaEE】线程的状态
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • ECMAScript6(0):ES6简明参考手册
  • isset在php5.6-和php7.0+的一些差异
  • JS基础之数据类型、对象、原型、原型链、继承
  • Making An Indicator With Pure CSS
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • react 代码优化(一) ——事件处理
  • Spring声明式事务管理之一:五大属性分析
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • Vue 重置组件到初始状态
  • Web设计流程优化:网页效果图设计新思路
  • 初识MongoDB分片
  • 力扣(LeetCode)21
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 浅谈web中前端模板引擎的使用
  • 什么是Javascript函数节流?
  • 通过git安装npm私有模块
  • 我感觉这是史上最牛的防sql注入方法类
  • Java性能优化之JVM GC(垃圾回收机制)
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • $ git push -u origin master 推送到远程库出错
  • (12)Linux 常见的三种进程状态
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (7)STL算法之交换赋值
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (算法)Travel Information Center
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .net 7 上传文件踩坑
  • .NET Core中Emit的使用
  • .net web项目 调用webService
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .考试倒计时43天!来提分啦!
  • /var/spool/postfix/maildrop 下有大量文件
  • [ vulhub漏洞复现篇 ] Jetty WEB-INF 文件读取复现CVE-2021-34429
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)
  • [ 转载 ] SharePoint 资料
  • [AIGC] Java 和 Kotlin 的区别
  • [C#][DevPress]事件委托的使用
  • [Editor]Unity Editor类常用方法