当尝试使用DocumentReference库对Firestore数据库中的Gson数据类型进行序列化/反序列化时,遇到以下异常。我正在使用通过模拟器运行的Google Play服务插件(版本4.0.1),gson库(版本2.8.5)和Nexus 5X API 25(Android 7.1.1(Google Play))虚拟设备。
W/System.err: java.lang.AssertionError: impossible
D/FA: Logging event (FE): session_start(_s), Bundle[{firebase_event_origin(_o)=auto, firebase_screen_class(_sc)=MainActivity, firebase_screen_id(_si)=-2086822989708624881}]
W/System.err: at java.lang.Enum$1.create(Enum.java:269)
at java.lang.Enum$1.create(Enum.java:260)
at libcore.util.BasicLruCache.get(BasicLruCache.java:58)
at java.lang.Enum.getSharedConstants(Enum.java:286)
at java.lang.Class.getEnumConstantsShared(Class.java:2291)
W/System.err: at java.lang.Class.getEnumConstants(Class.java:2279)
at com.google.gson.internal.bind.TypeAdapters$EnumTypeAdapter.<init>(TypeAdapters.java:779)
at com.google.gson.internal.bind.TypeAdapters$30.create(TypeAdapters.java:818)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:53)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.Gson.toJson(Gson.java:696)
at com.google.gson.Gson.toJson(Gson.java:683)
at com.google.gson.Gson.toJson(Gson.java:638)
at com.involveunation.involveu.data.cache.Serializer.serialize(Serializer.java:28)
W/System.err: at com.involveunation.involveu.data.cache.CacheImpl.put(CacheImpl.java:73)
at com.involveunation.involveu.data.repository.feed.FeedCloudDataStore.lambda$getFeedEntityData$2$FeedCloudDataStore(FeedCloudDataStore.java:57)
at com.involveunation.involveu.data.repository.feed.FeedCloudDataStore$$Lambda$0.apply(Unknown Source)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:121)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onNext(ObservableCreate.java:67)
at com.involveunation.involveu.data.network.FirebaseApiImplementation.lambda$null$0$FirebaseApiImplementation(FirebaseApiImplementation.java:74)
at com.involveunation.involveu.data.network.FirebaseApiImplementation$$Lambda$9.onComplete(Unknown Source)
at com.google.android.gms.tasks.zzj.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.NoSuchMethodException: values []
at java.lang.Class.getMethod(Class.java:1981)
at java.lang.Class.getDeclaredMethod(Class.java:1960)
at java.lang.Enum$1.create(Enum.java:265)
... 49 more
我能够使用以下代码正确检索DocumentReference并将其转换为我的ReferenceEntity类。
@Override
public Observable<FeedEntity> getFeedEntityData(String id) {
return this.firebaseApi.getDocument(this.firebaseFirestore.collection("feed").document(id))
.flatMap((DocumentSnapshot response) -> {
// Creates the ReferenceEntity by casting the result to class DocumentSnapshot.
ReferenceEntity referenceEntity = response.toObject(ReferenceEntity.class);
// Sets the id of the entity for getting it from the cache later.
referenceEntity.setId("ThrowawayId");
// Prints out the DocumentReference path from the database.
System.out.println("ownerReference = " + referenceEntity.getOwnerReference().getPath());
// Puts the newly made referenceEntity into the cache.
FeedCloudDataStore.this.cache.put(referenceEntity, ReferenceEntity.class);
// Gets the referenceEntity from the cache using its key (first parameter).
// This never gets called due to the exception being thrown in the method above.
FeedCloudDataStore.this.cache.get("ThrowawayId", ReferenceEntity.class);
...
});
}
这是ReferenceEntity类和BaseEntity类文件(@SerializedName批注用于gson,@ PropertyName批注用于Firestore):
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.PropertyName;
import com.google.gson.annotations.SerializedName;
public class ReferenceEntity extends BaseEntity {
public ReferenceEntity() {
}
@SerializedName("owner_ref")
private DocumentReference ownerReference;
@PropertyName("owner_ref")
public DocumentReference getOwnerReference() {
return ownerReference;
}
@PropertyName("owner_ref")
public void setOwnerReference(DocumentReference ownerReference) {
this.ownerReference = ownerReference;
}
}
...
public abstract class BaseEntity {
private String id;
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
}
由于print语句正确吐出,因此上述代码有效:
I/System.out: ownerReference = organizations/-Kd2GYk3EN9YI4FwmLyu
这是缓存方法和序列化方法:
@Override
public <T> void put(T entity, Class<T> clazz) {
if (entity != null) {
final File file = this.createFile(((BaseEntity) entity).getId());
if (!isCached(((BaseEntity) entity).getId())) {
final String json = this.serializer.serialize(entity, clazz);
...
}
}
}
...
public <T> String serialize(T entity, Class<T> clazz) {
return gson.toJson(entity, clazz);
}
上面的serialize方法中发生异常。在过去的几天里,我已经研究了这个问题,但尚未发现任何有用的东西。由于GeoPoint和Timestamp数据类型(它们均由简单的原语组成)不会发生此异常,因此可能是由于DocumentReference类的属性引起的。上面的代码对于我在项目中拥有的其他实体(任何没有Reference数据类型的实体)均正常工作。任何帮助,将不胜感激。谢谢。
解决方案:
与其对序列本身进行序列化/反序列化,请通过在引用上使用getPath()方法将其序列化为字符串,然后返回通过使用FirebaseFirestore.getInstance()。document()创建的DocumentReference对其进行序列化。这是执行此操作的Serializer类的完整代码:
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Json Serializer/Deserializer.
*/
@Singleton
public class Serializer {
private final Gson gson;
@Inject
Serializer() {
// Custom serializer that accepts a DocumentReference data type and returns the
// reference path as a string.
JsonSerializer<DocumentReference> referenceSerializer = (src, type, context) ->
src == null ? null : new JsonPrimitive(src.getPath());
// Custom deserializer that accepts a json string for the DocumentReference data type and
// returns a new DocumentReference that is created using the string reference path.
JsonDeserializer<DocumentReference> referenceDeserializer = (JsonElement json, Type type,
JsonDeserializationContext context) ->
json == null ? null : FirebaseFirestore.getInstance().document(json.getAsString());
// Builds the gson object using our custom DocumentReference serializer/deserializer above.
gson = new GsonBuilder()
.registerTypeAdapter(DocumentReference.class, referenceSerializer)
.registerTypeAdapter(DocumentReference.class, referenceDeserializer).create();
}
/**
* Serialize an object to Json.
*
* @param entity Object to serialize.
* @param clazz Type of the entity to serialize.
*/
public <T> String serialize(T entity, Class<T> clazz) {
return gson.toJson(entity, clazz);
}
/**
* Deserialize a json representation of an object.
*
* @param string Entity json string to deserialize.
* @param clazz Type of the entity to deserialize.
*/
public <T> T deserialize(String string, Class<T> clazz) {
return gson.fromJson(string, clazz);
}
}
答案 0 :(得分:1)
不要尝试直接序列化DocumentReference。您需要序列化的DocumenetReference中唯一重要的数据是路径字符串。如果将其序列化,则可以根据需要重新构造DocumentReference对象。
DocumentReference ref = ...
String path = ref.getPath();
DocumentReference ref2 = FirebaseFirestore.getInstance().document(path);
// Now ref and ref2 point to the same document