【问题标题】:Java Deserialize JSON with datetime to objectJava使用日期时间反序列化JSON到对象
【发布时间】:2021-01-27 21:21:16
【问题描述】:

我有问题。我有以下 JSON:

[
   {
      "Id":"8",
      "MasterAgentId":"0",
      "LastAgentStrategyId":"16116488969159",
      "BotState":"Active",
      "Owner":"Andre",
      "ExtraNotifiers":"",
      "Exchange":"lava",
      "DateTime":"2021-01-27 22:12:02",
      "AgentStatus":"Enabled",
      "ProtectiveOrdersEnabled":"yes",
      "Sim_Progress":"100",
      "Sim_DateTime":"2021-01-27 09:18:00",
      "Sim_Coin":"BTC",
      "Sim_Price":"31626.580000",
      "Sim_Profit":"1216.04",
      "Sim_Profit_Perc":"60.80",
      "Sim_StartDateTime":"2019-01-01 00:00:00",
      "LastAgentStrategyRun":"2020-12-19 17:40:30.531000"
   }
]

如您所见,我在 JSON 中有 4 个日期时间:DateTime, Sim_DateTime, Sim_StartDateTime, LastAgentStrategyRun

现在我为此创建了一个如下所示的类:

import java.time.LocalDateTime;

public class Agent {

    private int Id;
    private int MasterAgentId;
    private long LastAgentStrategyId;
    private AgentBotState BotState;
    private String Owner;
    private String ExtraNotifiers;
    private AgentExchanges Exchange;
    private LocalDateTime DateTime;
    private AgentStatus AgentStatus;
    private String ProtectiveOrdersEnabled;
    private String Sim_Progress;
    private String Sim_DateTime;
    private String Sim_Coin;
    private double Sim_Price;
    private double Sim_Profit;
    private double Sim_Profit_Perc;
    private LocalDateTime Sim_StartDateTime;
    private LocalDateTime LastAgentStrategyRun;
}

但是当我使用 GSON 反序列化 json 时:

Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<Agent>>() {}.getType();
ArrayList<Agent> agentList = new Gson().fromJson(jsonResponse, listType);

我收到以下错误:

但代码崩溃并出现以下错误:

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 157 path $[0].DateTime
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
    at com.google.gson.Gson.fromJson(Gson.java:810)
    at com.google.gson.Gson.fromJson(Gson.java:775)
    at com.google.gson.Gson.fromJson(Gson.java:724)
    at com.company.Main.main(Main.java:34)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 157 path $[0].DateTime
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:387)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:189)
    ... 9 more

现在,当我从 json 中删除所有日期时间时,它会正确解析,并且只有一些奇怪的警告:

警告:发生了非法反射访问操作警告: 非法反射访问 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory (文件:/C:/Users/Alexander/.m2/repository/com/google/code/gson/gson/2.3.1/gson-2.3.1.jar) 到字段 java.time.LocalDateTime.date 警告:请考虑 将此报告给 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory 警告: 使用 --illegal-access=warn 启用进一步非法的警告 反射访问操作警告:所有非法访问操作 将在未来的版本中被拒绝

如何将日期时间字符串解析为对象以及如何摆脱警告?

更新

使用以下代码后:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) -> {
    Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
    return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}).create();

Type listType = new TypeToken<ArrayList<Agent>>() {}.getType();
ArrayList<Agent> agentList = gson.fromJson(jsonResponse, listType);

我现在收到此错误:

Exception in thread "main" java.lang.NumberFormatException: For input string: "2021-01-27 22:56:01"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
    at java.base/java.lang.Long.parseLong(Long.java:707)
    at java.base/java.lang.Long.parseLong(Long.java:832)
    at com.google.gson.JsonPrimitive.getAsLong(JsonPrimitive.java:238)
    at com.company.Main.lambda$main$0(Main.java:35)
    at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
    at com.google.gson.Gson.fromJson(Gson.java:810)
    at com.google.gson.Gson.fromJson(Gson.java:775)
    at com.google.gson.Gson.fromJson(Gson.java:724)
    at com.company.Main.main(Main.java:40)

【问题讨论】:

  • 不是,不同的是他只想解析1个元素,我却把整个json解析成一个类。
  • 再次更新了我的答案以简化 DateTimeFormat 解析并考虑到您拥有的不同数据格式

标签: java json gson


【解决方案1】:

您需要注册 LocalDateTime:例如替换 Gson gson = new Gson(); 参见下面的代码:

更新了使用日期格式化程序解析 LocalDateTime 的答案,而不是创建 Instant。此外,您的日期格式并不一致,因为有些返回秒,有些返回毫秒,所以我提供了两种格式替代方案。

请查看使用简化代理类的示例代码

String jsonResponse = "[\n" +
            "   {\n" +
            "      \"DateTime\":\"2021-01-27 09:18:00\",\n" +
            "      \"Sim_StartDateTime\":\"2019-01-01 00:00:00\",\n" +
            "      \"LastAgentStrategyRun\":\"2020-12-19 17:40:30.531000\"\n" +
            "   }\n" +
            ']';

    Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) -> {

        try{
            return LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        } catch (DateTimeParseException e){
            return LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"));
        }

    }).create();

    Type listType = new TypeToken<ArrayList<Agent>>() {}.getType();
    ArrayList<Agent> agentList = gson.fromJson(jsonResponse, listType);

    System.out.println(agentList);

和代理类

public class Agent {
    private LocalDateTime DateTime;
    private LocalDateTime Sim_StartDateTime;
    private LocalDateTime LastAgentStrategyRun;

    public LocalDateTime getDateTime() {
        return DateTime;
    }

    public void setDateTime(LocalDateTime dateTime) {
        DateTime = dateTime;
    }

    public LocalDateTime getSim_StartDateTime() {
        return Sim_StartDateTime;
    }

    public void setSim_StartDateTime(LocalDateTime sim_StartDateTime) {
        Sim_StartDateTime = sim_StartDateTime;
    }

    public LocalDateTime getLastAgentStrategyRun() {
        return LastAgentStrategyRun;
    }

    public void setLastAgentStrategyRun(LocalDateTime lastAgentStrategyRun) {
        LastAgentStrategyRun = lastAgentStrategyRun;
    }

    @Override
    public String toString() {
        return "Agent{" +
                "DateTime=" + DateTime +
                ", Sim_StartDateTime=" + Sim_StartDateTime +
                ", LastAgentStrategyRun=" + LastAgentStrategyRun +
                '}';
    }
}

和输出

[Agent{DateTime=2021-01-27T09:18, Sim_StartDateTime=2019-01-01T00:00, LastAgentStrategyRun=2020-12-19T17:40:30.531}]

【讨论】:

  • 我需要把它放在主要位置吗?对于我拥有的每个领域?
  • 不,您不需要这样做。未经测试,我不确定代码是否应该使用 LocalDate 或 LocalDateTime
  • 刚刚修改了我的答案
  • 我仍然不知道我需要把这个放在哪里?
  • 在你的代码中而不是 Gson gson = new Gson();使用上面的代码获取一个通过builder注册的类型的gson对象。
【解决方案2】:

您可以使用GsonUtils。但请注意以下问题:您在此字段中有 不同 日期/时间格式。这是不正确的,因为要解析此文件,您必须使用所需的模板设置日期/时间格式化程序。我在LastAgentStrategyRun 字段中更改了格式,这是一个示例:

String json = "[\n" +
        "   {\n" +
        "      \"Id\":\"8\",\n" +
        "      \"MasterAgentId\":\"0\",\n" +
        "      \"LastAgentStrategyId\":\"16116488969159\",\n" +
        "      \"BotState\":\"Active\",\n" +
        "      \"Owner\":\"Andre\",\n" +
        "      \"ExtraNotifiers\":\"\",\n" +
        "      \"Exchange\":\"lava\",\n" +
        "      \"DateTime\":\"2021-01-27 22:12:02\",\n" +
        "      \"AgentStatus\":\"Enabled\",\n" +
        "      \"ProtectiveOrdersEnabled\":\"yes\",\n" +
        "      \"Sim_Progress\":\"100\",\n" +
        "      \"Sim_DateTime\":\"2021-01-27 09:18:00\",\n" +
        "      \"Sim_Coin\":\"BTC\",\n" +
        "      \"Sim_Price\":\"31626.580000\",\n" +
        "      \"Sim_Profit\":\"1216.04\",\n" +
        "      \"Sim_Profit_Perc\":\"60.80\",\n" +
        "      \"Sim_StartDateTime\":\"2019-01-01 00:00:00\",\n" +
        "      \"LastAgentStrategyRun\":\"2020-12-19 17:40:30\"\n" +
        "   }\n" +
        ']';

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
GsonDecorator gson = GsonHelper.createGsonDecorator(new GsonBuilderDecorator().withDateTimeFormatter(formatter));
List<Agent> agent = gson.readList(json, Agent.class);

【讨论】:

  • 如何从 GitHub 安装 GsonUtils?我正在使用 IntelliJ。搜索时找不到maven库
  • 这次你必须下载它,然后使用gradle 构建它并将jar 添加到你的项目中。如果你要使用这个工具,我可以将它添加到 Maven 中。
  • 我真的很想使用它,因为它看起来更容易。你能把它添加到maven吗?
  • 好的,但你必须先为你的 json 测试它。我可以看到您在字段中有不同的时间格式。
  • 我正在努力将它安装为 gradle,你能把它上传到 Maven,所以我可以从那里安装它吗?它可能会起作用,因为您使用我的 JSON 对其进行了测试!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多