将泛型与Firebase一起使用的最佳做法snapshot.getValue()

时间:2018-01-13 07:20:33

标签: java generics firebase-realtime-database

TL; DR:如何正确使用Firebase DataSnapshot.getValue()的泛型类?

用例:我想使用Firebase为我的所有实体(其中一组)实现单个通用远程数据源类。在收听数据更改时,我希望将datasnapshot中的值作为E类型的对象(其类型在别处确定),但我不知道它是否可以使用Firebase查询,如下所示:

public class GenRemoteDataSource<E extends SomeClass>
{
   //...
   public void onDataChange(DataSnapshot dataSnapshot)
   {
        E item = (E) dataSnapshot.getValue(); // <- unchecked cast and it doesn't work
        items.add(item);
   }
}

例如,我有一个扩展SomeClass的Foo类,并且这个GenRemoteDataSource的实现与一个Foo类将是:

public class Foo extends SomeClass{}

public class FooRemoteDataSource extends GenRemoteDataSource<Foo>
{
   //...
}

但Firebase会抛出运行时错误,因为它不会将getValue()强制转换为Foo,而是尝试将值转换为上限SomeClass。我很困惑为什么会这样:

Java.lang.ClassCastException: java.util.HashMap cannot be cast to com.example.app.SomeClass

请告知我应该如何使用Type-safety(没有未选中的演员表)。谢谢。

编辑以下内容与此无关,请参阅GenericTypeIndicator

<击> 的修改 我也试过(盲目地,值得一试)GenericTypeIndicator,

GenericTypeIndicator<E> mTypeIndicator = new GenericTypeIndicator<>();
E item = dataSnapshot.getValue(mTypeIndicator);

但它反而吐出以下运行时错误。

com.google.firebase.database.DatabaseException: Not a direct subclass of GenericTypeIndicator: class java.lang.Object

<击>

1 个答案:

答案 0 :(得分:2)

TL; DR我的解决方案,(引入更多的依赖性而不是语义上必需的?)

public class GenRemoteDataSource<E extends SomeClass>
{
   //...
   private final Class<E> clazz;

   GenRemoteDataSource(Class<E> clazz)
   {
      this.clazz = clazz;
   }

   //...
   public void onDataChange(DataSnapshot dataSnapshot)
   {
        E item = dataSnapshot.getValue(clazz); // <- now is type safe.
        items.add(item);
   }
}

我最后通过构造函数注入向getValue()提供了类定义。这是通过将Class<T>传递给泛型类的构造函数并将其设置为Firebase的getValue()以用作实例参数来完成的。请评论是否有更好的解决方案,因为对我来说这似乎是多余的。谢谢!