Облачные функции Google — Триггер базы данных в реальном времени — как десериализовать данные JSON в POJO?

# #kotlin #firebase-realtime-database #google-cloud-functions #gson

Вопрос:

Как описано в документах Google Cloud Functions, можно запускать функцию на основе событий базы данных Firebase в реальном времени (запись/создание/обновление/удаление).

В следующем примере документов объясняется, как получить дельта-снимок.

 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 amp;amp; body.has("auth")) {
      JsonObject authObj = body.getAsJsonObject("auth");
      isAdmin = authObj.has("admin") amp;amp; authObj.get("admin").getAsBoolean();
    }

    logger.info("Admin?: "   isAdmin);

    if (body != null amp;amp; 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 имеет List<T> поле, а база данных Firebase всегда преобразует списки в карты с целочисленными ключами.

Я предпочтительно не хочу менять каждый List<T> на Map<Int,T> , потому что у меня много занятий 🙁

Заранее спасибо!

Комментарии:

1. Пытаетесь прочитать данные в Android?

2. Нет, я читаю это в облачной функции (функция RawBackgroundFunction), как и в примере, но с использованием Kotlin.

Ответ №1:

Итак, вот что я в итоге сделал (возможно, не лучшее решение!):

1) Создайте пользовательский десериализатор Json для списков, входящих в Firebase:

 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) Аннотируйте каждый список в моем POJO @JsonAdapter(ListFirebaseDeserializer::class) , например:

 class MyCustomObject {

    @JsonAdapter(ListFirebaseDeserializer::class)
    var myPaymentList = ArrayList<Payment>()
}
 

Это может быть неприятно, если у вас уже есть много списков для аннотирования, но это лучше, чем вместо этого использовать карты.

Надеюсь, это поможет!