Gson java.time.LocalDateTime序列化错误

问题描述 投票:0回答:2

我正在尝试用谷歌 Gson 库序列化一个类。

public class XYZ {
    private String name;
    private LocalDateTime timeCreated;
}

当我尝试执行时出现错误

return gson.toJson(this.obj);

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.time.LocalDate java.time.LocalDateTime.date accessible: module java.base does not "opens java.time" to unnamed module @1d8bd0de

使用 java18-corretto

我认为谷歌 Gson lib 中存在问题。

java datetime serialization gson
2个回答
0
投票

你可以尝试改变:

public class XYZ {
    private String name;
    private LocalDateTime timeCreated;
}

致:

public class XYZ {
    public String name;
    public LocalDateTime timeCreated;
}

我已经在我的案例中这样做了,而且效果很好!


0
投票

Instant
,不是
LocalDateTime

实际上,

LocalDateTime
是用于跟踪“创建时”值的错误类。该类缺少时区或与 UTC 的偏移量的上下文,因此它不能表示时刻,即时间轴上的特定点。
LocalDateTime
本质上是模棱两可的。

而是使用

Instant
类。这个类代表了一个时刻,与 UTC 的偏移量为零小时-分钟-秒。

Gson 适配器

我不经常使用 Gson,所以我可能错了,但是......很奇怪 Gson 显然仍然缺乏对 java.time 的支持。尽管 JSR 310 多年前就被采用,早在 Java 8 中。

为了解决 Gson 中的不足,您需要导入一些提供 java.time 类型的库,或者您可以轻松 👉🏾 编写自己的适配器。

让我们从

Person
课开始。

注意两个成员字段

name
createdAt
如何标记
private
,就像你的问题中的字段一样。

还要注意这个类是如何不可变的,有 getter 但没有 setter。 Gson 仍然可以通过 Java Reflection 的魔力重构这个类的对象。这也是为什么您也可以将此类定义为短的单行record

public record Person ( String name , Instant createdAt ) {}
.

package work.basil.example.gson;

import java.time.Instant;
import java.util.Objects;

public final class Person
{
    private final String name;
    private final Instant createdAt;

    public Person ( String name , Instant createdAt )
    {
        this.name = name;
        this.createdAt = createdAt;
    }

    public String name ( ) { return name; }

    public Instant createdAt ( ) { return createdAt; }

    @Override
    public boolean equals ( Object obj )
    {
        if ( obj == this ) { return true; }
        if ( obj == null || obj.getClass() != this.getClass() ) { return false; }
        var that = ( Person ) obj;
        return Objects.equals( this.name , that.name ) &&
               Objects.equals( this.createdAt , that.createdAt );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( name , createdAt );
    }

    @Override
    public String toString ( )
    {
        return "Person[" +
               "name=" + name + ", " +
               "createdAt=" + createdAt + ']';
    }
}

我们为

Instant
类型写了一个适配器。我们使用标准 ISO 8601 格式作为序列化值。这种格式化字符串末尾的
Z
+00:00
的缩写,表示与 UTC 的零小时-分钟-秒的偏移量。

package work.basil.example.gson;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.time.Instant;

public class Gson_InstantTypeAdapter extends TypeAdapter < Instant >
{
    @Override
    public void write ( JsonWriter jsonWriter , Instant instant ) throws IOException
    {
        jsonWriter.value( instant.toString() );  // Writes in standard ISO 8601 format.
    }

    @Override
    public Instant read ( JsonReader jsonReader ) throws IOException
    {
        return Instant.parse( jsonReader.nextString() );   // Parses standard ISO 8601 format.
    }
}

我们写了一个应用程序来展示那些正在行动的人。

注意我们如何为

Instant
类型注册我们的适配器。

package work.basil.example.gson;

import com.google.gson.*;

import java.time.Instant;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        Gson gson =
                new GsonBuilder()
                        .registerTypeAdapter( Instant.class , new Gson_InstantTypeAdapter() )
                        .create();

        // Write to JSON.
        Person person = new Person( "John Doe" , Instant.now() ); //For example: 2022-02-02T11:11:510Z
        String personAsJson = gson.toJson( person );

        System.out.println( "personAsJson = " + personAsJson );

        // Parse JSON.
        Person p = gson.fromJson( personAsJson , Person.class );

        System.out.println( "p.toString() = " + p );
    }
}

运行时:

personAsJson = {"name":"John Doe","createdAt":"2023-03-28T06:56:18.867974Z"}
p.toString() = Person[name=John Doe, createdAt=2023-03-28T06:56:18.867974Z]
© www.soinside.com 2019 - 2024. All rights reserved.