如何使用 Gson 将 HashMap 与 Json 相互转换?

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

背景

我只想将一些 JSON 保存并加载为字符串,源自

<LocalDate,Int>

的 HashMap

问题

虽然我成功从 HashMap 生成 JSON 字符串,但我无法执行相反的操作,即从 JSON 字符串生成 HashMap。

我尝试过的事情

这就是我转换为 Json 字符串的方法:

val gson = Gson()
val type = object:TypeToken<Map<LocalDate, Int>>(){}.type
val map: HashMap<LocalDate, Int> = HashMap()
val today = LocalDate.now()
map[today] = 1
val jsonStr = gson.toJson(map, type) // example of what this has: "{"2024-01-01":1}"

我也可以用它来看看确实应该可以解析字符串:

val jsonObject = JSONObject(jsonStr)

还要检查其中的值:

val countForToday = jsonObject.getInt(today.toString())

但是,当我使用这个时(查看这里之后):

var newMap: Map<LocalDate, Int> = gson.fromJson(jsonStr, object : TypeToken<Map<LocalDate, Int>>() {}.type)

我得到这个例外:

Method threw 'com.google.gson.JsonSyntaxException' exception.
IllegalStateException: Expected BEGIN_OBJECT but was STRING at line...

根据我从其他示例中看到的内容,我尝试过的所有方法都失败了:

  1. 我尝试使用
    GsonBuilder().create()
    而不仅仅是
    Gson()
    。我认为这并不重要,尽管
    Gson()
    可能是一个可以在任何地方使用的单例,甚至可能也是线程安全的。
  2. 使用
    Map
    代替HashMap,使用
    Any
    代替
    Int
    ,使用
    ?
    (可为空)。我能想到的所有各种组合...

现在我使用这个解决方法,不使用 Gson 转换回 HashMap:

val jsonObject = JSONObject(jsonStr)
val hashHap = HashMap<LocalDate, Int>()
jsonObject.keys().forEach { key: String ->
    val date = LocalDate.parse(key)
    val value = jsonObject.getInt(key)
    hashHap[date] = value
}

这可行,但我想知道为什么 Gson 失败了。

问题

发生什么事了?为什么我不能将这个简单的转换回 HashMap/Map(使用 Gson)?

java json kotlin hashmap gson
1个回答
0
投票

您似乎在转换时遇到问题

LocalDate
。 您需要有一个自定义的日期序列化器和反序列化器。 它看起来会像这样:

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 *
 * @author asgar
 */
public class LocalDateConverter implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> {

    @Override
    public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(DateTimeFormatter.ISO_LOCAL_DATE.format(src));
    }

    @Override
    public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        return DateTimeFormatter.ISO_LOCAL_DATE.parse(json.getAsString(), LocalDate::from);
    }
}

之后就可以使用了。这是示例代码:

public static void main(String[] args) {
        GsonBuilder builder = new GsonBuilder();

        builder.registerTypeAdapter(new TypeToken<LocalDate>() {}.getType(), new LocalDateConverter());
        Gson gson1 = builder.create();
        
        String jsonString = "{\"2023-01-01\":10,\"2023-02-15\":20,\"2023-05-08\":15,\"2023-08-20\":30}";
        Type type = new TypeToken<HashMap<LocalDate, Integer>>() {
        }.getType();
        Map<LocalDate, Integer> map = gson1.fromJson(jsonString, type);

        System.out.println("HashMap1: " + map);
    }
    
© www.soinside.com 2019 - 2024. All rights reserved.