Google Cloud Functions - 实时数据库触发器 - 如何将数据 JSON 反序列化为 POJO?
Google Cloud Functions - Realtime Database Trigger - how to deserialize data JSON to POJO?
如 Google 云函数 docs 中所述,可以根据 Firebase 实时数据库事件 (write/create/update/delete) 触发函数。
以下文档 sample 解释了如何获取 delta 快照。
public class FirebaseRtdb implements RawBackgroundFunction {
private static final Logger logger = Logger.getLogger(FirebaseRtdb.class.getName());
// Use GSON (https://github.com/google/gson) to parse JSON content.
private static final Gson gson = new Gson();
@Override
public void accept(String json, Context context) {
logger.info("Function triggered by change to: " + context.resource());
JsonObject body = gson.fromJson(json, JsonObject.class);
boolean isAdmin = false;
if (body != null && body.has("auth")) {
JsonObject authObj = body.getAsJsonObject("auth");
isAdmin = authObj.has("admin") && authObj.get("admin").getAsBoolean();
}
logger.info("Admin?: " + isAdmin);
if (body != null && body.has("delta")) {
logger.info("Delta:");
logger.info(body.get("delta").toString());
}
}
}
示例完美运行,但问题是:如何将此增量反序列化为 POJO?
我试过了:
val mObject = gson.fromJson(body.get("delta").toString(), MyCustomObject::class.java)
但我得到:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
据我所知,这是因为 MyObject class 有一个 List<T>
字段,而 Firebase 数据库总是将列表转换为具有整数键的地图。
我最好不要将每个 List<T>
更改为 Map<Int,T>
,因为我有很多 classes :(
提前致谢!
所以,这就是我最终所做的 (可能不是最好的解决方案!):
1) 为 Firebase 即将到来的列表创建自定义 Json 反序列化器:
class ListFirebaseDeserializer<T> : JsonDeserializer<ArrayList<T>> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ArrayList<T> {
val result = ArrayList<T>()
val typeOfElement = (typeOfT as ParameterizedType).actualTypeArguments[0]
json?.let {
json.asJsonObject.entrySet().forEach {
entry->
result.add(Gson().fromJson(entry.value, typeOfElement))
}
}
return result
}
}
这会将 Firebase 转换为地图的列表并将其转换回实际列表。
2) 用 @JsonAdapter(ListFirebaseDeserializer::class)
注释我的 POJO 中的每个列表,例如:
class MyCustomObject {
@JsonAdapter(ListFirebaseDeserializer::class)
var myPaymentList = ArrayList<Payment>()
}
如果您已经有很多列表要注释,这可能会很痛苦,但这比必须使用地图更好。
希望对您有所帮助!
如 Google 云函数 docs 中所述,可以根据 Firebase 实时数据库事件 (write/create/update/delete) 触发函数。
以下文档 sample 解释了如何获取 delta 快照。
public class FirebaseRtdb implements RawBackgroundFunction {
private static final Logger logger = Logger.getLogger(FirebaseRtdb.class.getName());
// Use GSON (https://github.com/google/gson) to parse JSON content.
private static final Gson gson = new Gson();
@Override
public void accept(String json, Context context) {
logger.info("Function triggered by change to: " + context.resource());
JsonObject body = gson.fromJson(json, JsonObject.class);
boolean isAdmin = false;
if (body != null && body.has("auth")) {
JsonObject authObj = body.getAsJsonObject("auth");
isAdmin = authObj.has("admin") && authObj.get("admin").getAsBoolean();
}
logger.info("Admin?: " + isAdmin);
if (body != null && body.has("delta")) {
logger.info("Delta:");
logger.info(body.get("delta").toString());
}
}
}
示例完美运行,但问题是:如何将此增量反序列化为 POJO?
我试过了:
val mObject = gson.fromJson(body.get("delta").toString(), MyCustomObject::class.java)
但我得到:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
据我所知,这是因为 MyObject class 有一个 List<T>
字段,而 Firebase 数据库总是将列表转换为具有整数键的地图。
我最好不要将每个 List<T>
更改为 Map<Int,T>
,因为我有很多 classes :(
提前致谢!
所以,这就是我最终所做的 (可能不是最好的解决方案!):
1) 为 Firebase 即将到来的列表创建自定义 Json 反序列化器:
class ListFirebaseDeserializer<T> : JsonDeserializer<ArrayList<T>> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ArrayList<T> {
val result = ArrayList<T>()
val typeOfElement = (typeOfT as ParameterizedType).actualTypeArguments[0]
json?.let {
json.asJsonObject.entrySet().forEach {
entry->
result.add(Gson().fromJson(entry.value, typeOfElement))
}
}
return result
}
}
这会将 Firebase 转换为地图的列表并将其转换回实际列表。
2) 用 @JsonAdapter(ListFirebaseDeserializer::class)
注释我的 POJO 中的每个列表,例如:
class MyCustomObject {
@JsonAdapter(ListFirebaseDeserializer::class)
var myPaymentList = ArrayList<Payment>()
}
如果您已经有很多列表要注释,这可能会很痛苦,但这比必须使用地图更好。
希望对您有所帮助!