How to catch java.lang.RuntimeException: Could not deserialize object from Firebase ClassMapper and add default Values

狂风中的少年 提交于 2020-01-05 10:10:31

问题


I am using Firebase UI Recycler Adapter to read data from Firestore

FirestoreRecyclerOptions<Transaction> options =
                new FirestoreRecyclerOptions.Builder<Transaction>()
                        .setQuery(mQuery, Transaction.class)
                        .setLifecycleOwner(this)
                        .build();

        mAdapter = new TransactionAdapter(options, this, getActivity()) {

            @Override
            public void onDataChanged() {
                // Show/hide content if the query returns empty.
                if (getItemCount() == 0) {
                    mRestaurantsRecycler.setVisibility(View.GONE);
                    mEmptyView.setVisibility(View.VISIBLE);
                } else {
                    mRestaurantsRecycler.setVisibility(View.VISIBLE);
                    mEmptyView.setVisibility(View.GONE);
                }
            }

            @Override
            public void onError(FirebaseFirestoreException e) {
                Log.e("Error", ", not initializing RecyclerView",e);
            }
        };
        Log.w("Test", "No6 query, not initializing RecyclerView");
        mRestaurantsRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
        mRestaurantsRecycler.setAdapter(mAdapter);

i am getting below exception for some corrupted fields in Firestore

java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to double (found in field 'amount')
    at com.google.firebase.firestore.util.CustomClassMapper.deserializeError(com.google.firebase:firebase-firestore@@17.1.4:524)
    at com.google.firebase.firestore.util.CustomClassMapper.convertDouble(com.google.firebase:firebase-firestore@@17.1.4:427)
    at com.google.firebase.firestore.util.CustomClassMapper.deserializeToPrimitive(com.google.firebase:firebase-firestore@@17.1.4:304)
    at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-firestore@@17.1.4:215)
    at com.google.firebase.firestore.util.CustomClassMapper.deserializeToType(com.google.firebase:firebase-firestore@@17.1.4:180)
    at com.google.firebase.firestore.util.CustomClassMapper.access$200(com.google.firebase:firebase-firestore@@17.1.4:53)
    at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-firestore@@17.1.4:700)
    at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-firestore@@17.1.4:674)
    at com.google.firebase.firestore.util.CustomClassMapper.convertBean(com.google.firebase:firebase-firestore@@17.1.4:503)
    at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-firestore@@17.1.4:242)
    at com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-firestore@@17.1.4:97)
    at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:203)
    at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:121)
    at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:183)
    at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:101)
    at com.firebase.ui.firestore.ClassSnapshotParser.parseSnapshot(ClassSnapshotParser.java:23)
    at com.firebase.ui.firestore.ClassSnapshotParser.parseSnapshot(ClassSnapshotParser.java:12)
    at com.firebase.ui.common.BaseCachingSnapshotParser.parseSnapshot(BaseCachingSnapshotParser.java:35)
    at com.firebase.ui.common.BaseObservableSnapshotArray.get(BaseObservableSnapshotArray.java:52)
    at com.firebase.ui.firestore.FirestoreRecyclerAdapter.getItem(FirestoreRecyclerAdapter.java:83)
    at com.firebase.ui.firestore.FirestoreRecyclerAdapter.onBindViewHolder(FirestoreRecyclerAdapter.java:125)
    at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
    at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
    at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5647)
    at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5913)
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
    at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1559)
    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
    at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
    at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3225)
    at android.view.View.measure(View.java:22071)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6602)
    at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:739)

I know why this error is thrown and i also know i can correct this if i correct my amount field in Firestore Database or by having a Cloud Function to check data validation etc.

But I don't want an App crash experience. Is there any way to catch and add any default value or Null for corrupted values. Showing an individual Null or NA field or an entire empty screen is always better than a Crash.

EDIT: In order to set a default value and avoid Runtime exception i have tried this with my Model class. I still don't know if there is a way to catch this exception.

public double amount;
public double getAmount() {
    return amount;
}
// If you change it Object, ClassMapper will not throw any exception and 
// You can parse any data type by yourself and also set a default value.
public void setAmount(Object amount) {
    try {
        // You can also add  instanceOf check
        this.amount = Double.parseDouble(amount.toString());
    } catch (Exception e) {
        // Set your default value
        this.amount = 0.00;
    }
}

回答1:


I'm answering this question becase of your request from here. So because I see that you are using the Firebase-UI library, there is no need to use a try-catch block. As also @FrankvanPuffelen mentioned in his comment, the simplest thing that you can do, is to override the onError method in your adapter class like this:

FirestoreRecyclerAdapter adapter = new FirestoreRecyclerAdapter<Chat, ChatHolder>(options) {
    @Override
    public void onDataChanged() {
        //Called each time there is a new query snapshot.
    }

    @Override
    public void onError(FirebaseFirestoreException e) {
        //Handle the error
        Log.d(TAG, e.getMessage());
    }
};


来源:https://stackoverflow.com/questions/53849305/how-to-catch-java-lang-runtimeexception-could-not-deserialize-object-from-fireb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!