【问题标题】:JsonSerializer<Date>() is not working for java.util.Date field when there is JsonSerializer<Timestamp>()当有 JsonSerializer<Timestamp>() 时,JsonSerializer<Date>() 不适用于 java.util.Date 字段
【发布时间】:2020-03-20 11:21:41
【问题描述】:

在我的 java 应用程序中,我使用 JsonSerializer 和 JsonSerializer() 分别序列化 java.util.Date 和 java.sql.Timestamp 字段。但问题是,当我使用 gson 将对象解析为 json 字符串时 java. util.Date 字段使用 JsonSerializer() 序列化程序而不是 JsonSerializer。 下面是我的代码。

Gson gson;
GsonBuilder builder;
SimpleDateFormat dtf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dtfDate=new SimpleDateFormat("yyyy-MM-dd");
builder = new GsonBuilder();

builder.registerTypeAdapter(Timestamp.class, new JsonSerializer<Timestamp>() {
    @Override
    public JsonElement serialize(Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
        dtf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String jsDate = dtf.format(src);
        System.out.println("Timestamp : src - "+src+" jsDate - "+jsDate+" typeOfSrc - "+typeOfSrc);
        return new JsonPrimitive(jsDate);
    }
});
builder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        String jsDate = dtfDate.format(src);
        System.out.println("Date : src - "+src+" jsDate - "+jsDate+" typeOfSrc - "+typeOfSrc);
        return new JsonPrimitive(jsDate);
    }
});
gson = builder.create();
PersonSubstitution  personSubstitution = loopDao.getPersonSubstitution(Integer.parseInt(deptId),date);
String jsonAccts = gson.toJson(personSubstitution, PersonSubstitution.class);

PersonSubstitution.class :

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Objects;


@Entity
@Table(name = "person_substitution")
public class PersonSubstitution implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Departments deptId;

    @Column(name = "date")
    private Date date;

    @JoinColumn(name = "staff_id", referencedColumnName = "person_id", nullable = false)
    @OneToOne(optional = false)
    private Person staffId;

    @Column(name = "created_on")
    private Timestamp createdOn;

    public PersonSubstitution() {

    }

    public PersonSubstitution(int id, Departments deptId, Date date, Person staffId, Timestamp createdOn) {
        this.id = id;
        this.deptId = deptId;
        this.date = date;
        this.staffId = staffId;
        this.createdOn = createdOn;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Departments getDeptId() {
        return deptId;
    }

    public void setDeptId(Departments deptId) {
        this.deptId = deptId;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Person getStaffId() {
        return staffId;
    }

    public void setStaffId(Person staffId) {
        this.staffId = staffId;
    }

    public Timestamp getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Timestamp createdOn) {
        this.createdOn = createdOn;
    }
}

我将System.out.println() 放入两个序列化程序中,并且只有时间戳干的工作如下:

Timestamp : src - 2019-11-28 00:00:00.0 jsDate - 2019-11-27 18:30:00 typeOfSrc - class java.sql.Timestamp
Timestamp : src - 2019-11-25 12:08:14.0 jsDate - 2019-11-25 06:38:14 typeOfSrc - class java.sql.Timestamp

那么日期字段有什么方法可以使用builder.registerTypeAdapter(Date.class, new JsonSerializer&lt;Date&gt;() {...} 而不是builder.registerTypeAdapter(Date.class, new JsonSerializer&lt;Timestamp&gt;() {...} ??

【问题讨论】:

  • 您使用哪个版本的Gson?你能创建一个重新创建错误的简单测试吗?你能显示一个生成的JSON 吗?
  • @MichałZiober com.google.code.gson:gson:2.8.1
  • 我已经尝试过使用版本2.8.5 并且一切正常。你能升级你的版本吗?
  • @MichałZiober 您是否尝试过使用序列化程序来处理日期和时间戳?
  • 是的,这两个属性都使用相关的序列化器进行序列化。

标签: java json date timestamp gson


【解决方案1】:

它是这样工作的,因为在运行时 datecreatedOnTimestamp。您需要将给定的序列化程序分配给一个字段。因此,您需要创建一个自定义序列化程序:

class DateJsonSerializer implements JsonSerializer<Date> {

    private final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        String formatted = formatter.get().format(src);

        return new JsonPrimitive(formatted);
    }
}

Timestamp序列化器:

class TimestampJsonSerializer implements JsonSerializer<Timestamp> {

    private final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        return dateFormat;
    });

    @Override
    public JsonElement serialize(Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
        String formatted = formatter.get().format(src);
        return new JsonPrimitive(formatted);
    }
}

并为Date 字段声明它:

@JsonAdapter(DateJsonSerializer.class)
private Date date;

您仍然可以将其注册为 Date 类的全局序列化程序:

Gson gson = new GsonBuilder()
        .setPrettyPrinting()
        .registerTypeAdapter(Timestamp.class, new TimestampJsonSerializer())
        .registerTypeAdapter(Date.class, new DateJsonSerializer())
        .create();

注意:我使用ThreadLocal是因为SimpleDateFormat不是线程安全的。

【讨论】:

  • 哦,终于成功了。你救了我的命。你能把时间戳序列化器也包括进来吗??
  • 谢谢。 setPrettyPrinting() 是什么意思?
  • @KJEjava48,它格式化JSON 输出。不要仅出于测试目的在生产中使用它。无需额外工具即可轻松阅读JSON
  • 你的意思是什么??那么我应该在生产中使用什么??
  • 你能建议我在生产环境中尝试什么吗??
猜你喜欢
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 2016-06-26
  • 1970-01-01
  • 2019-09-18
  • 2014-07-16
相关资源
最近更新 更多