Android-Expected a List while deserializing, but got a class java.util.HashMap-ThrowExceptions

Exception or error:

I want to get all list of restaurants from Firebase in android.
my database

Here is my code:

boolean delivery;
String openTime, closeTime, restaurantName;
long likes;
List<String> utilities;

List<RestaurantModel> listRes;

DatabaseReference dataResReference;

public RestaurantModel(){
    dataResReference = FirebaseDatabase.getInstance().getReference().child("restaurants");
}

public List<RestaurantModel> getallRestaurant(){

    listRes = new ArrayList<>();
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dataValues : dataSnapshot.getChildren()){
                    RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
                    listRes.add(restaurantModel);
                }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    };
    dataResReference.addListenerForSingleValueEvent(valueEventListener);
    return  listRes;
}

But i get an exception

Expected a List while deserializing, but got a class java.util.HashMap

at RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);

Update:
Base on Alex Mamo answser, i changed my code is:

public void getAllRestaurant(final WhereInterface whereInterface){
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            //go to node restaurant because datasnapshot is parent node
            DataSnapshot dataSnapshotRes = dataSnapshot.child("restaurants");
            //

            for (DataSnapshot valueRes : dataSnapshotRes.getChildren()){
                RestaurantModel restaurantModel = valueRes.getValue(RestaurantModel.class);
                whereInterface.getAllRestaurantModel(restaurantModel);

            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    };
    databaseReferenceRoot.addListenerForSingleValueEvent(valueEventListener);
}

But i still got this exception (:.

Anyone can know why?

And are there solution?

Thank you so much!

How to solve:

There are two problems in your code. The first one would be this error:

Expected a List while deserializing, but got a class java.util.HashMap

Which can be solved using the following lines of code:

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        List<RestaurantModel> listRes = new ArrayList<>();

        for (DataSnapshot dataValues : dataSnapshot.getChildren()){
            RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
            listRes.add(restaurantModel);
        }

        //Do what you need to do with listRes
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); //Don't ignore errors
    }
};
dataResReference.addListenerForSingleValueEvent(valueEventListener);

And the second problem is that you cannot return something now that hasn’t been loaded yet. Firebase APIs are asynchronous, meaning that onDataChange() method returns immediately after it’s invoked, and the callback from the Task it returns will be called sometime later. There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available. Because that method returns immediately, your listRes list you’re trying to return, will be empty due to the asynchronous behavior of this method.

Basically, you’re trying to return a value synchronously from an API that’s asynchronous. That’s not a good idea. You should handle the APIs asynchronously as intended.

A quick solution to this problem would be to use the listRes list only inside the onDataChange() method (as in the above lines of code), otherwise I recommend you see the last part of my answer from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Edit:

public void getAllRestaurant(){
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            List<RestaurantModel> listRestaurant = new ArrayList<>();

            for (DataSnapshot valueRes : dataSnapshot.getChildren()){
                RestaurantModel restaurantModel = valueRes.getValue(RestaurantModel.class);
                Log.d("Test", restaurantModel.getRestaurantName());
                listRestaurant.add(restaurantModel);
            }

            //Do what you need to do with listRes
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            throw databaseError.toException();
        }
    };
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();        
    rootRef.child("restaurants").addListenerForSingleValueEvent(valueEventListener);
}

###

I know this can be too late, but I wish my answer could help somebody. I know 2 ways to solve this problem. Once I have time I’ll update my answer .

#Solution 1

First of all I copy & paste your code. It is not clear for me how did you add data to firebase, but I feel you added data directly to firebase.

so this is My MainActivity code :

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RestaurantModel rm;
        List<String> utils;

        //restaurant 1
        rm = new RestaurantModel();
        rm.closeTime = "12:00am";
        rm.openTime = "12:00pm";
        rm.delivery = true;
        rm.likes = 300;
        rm.restaurantName = "KFC";
        utils = new ArrayList<>();
        utils.add("free wifi");
        utils.add("free Parking");
        utils.add("free water");
        rm.utilities = utils;

        //write first restaurant to Firebase
        rm.addRestaurantToFirebase(rm);


        //restaurant 2
        rm = new RestaurantModel();
        rm.closeTime = "5:00am";
        rm.openTime = "12:00pm";
        rm.delivery = false;
        rm.likes = 500;
        rm.restaurantName = "SubWay";
        utils = new ArrayList<>();
        utils.add("free wifi");
        utils.add("free Parking");

        rm.utilities = utils;

        //write Second restaurant to Firebase
        rm.addRestaurantToFirebase(rm);


        rm.getallRestaurant();

    }

}

and this is RestaurantModel :

public class RestaurantModel {
    public boolean delivery;
    public String openTime;
    public String closeTime;
    public String restaurantName;
    public long likes;
    public List<String> utilities;


    public List<RestaurantModel> listRes;

    DatabaseReference dataResReference;

    public RestaurantModel() {
        dataResReference = FirebaseDatabase.getInstance().getReference().child("restaurants");
    }

    public List<RestaurantModel> getallRestaurant() {
        listRes = new ArrayList<>();

        ValueEventListener valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dataValues : dataSnapshot.getChildren()) {
                    RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
                    listRes.add(restaurantModel);

                    Log.d("restaurantModel", restaurantModel.restaurantName);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        dataResReference.addListenerForSingleValueEvent(valueEventListener);
        return listRes;
    }


    public void addRestaurantToFirebase(RestaurantModel rm) {
        dataResReference.child(restaurantName).setValue(rm);
    }

}

here the result in firebase

###

Kotlin Example
This is a example to get all your nested data out of firebase real time database.

There are many tokens in this example and every token contains list of notes

enter image description here

 val noteListener = object : ValueEventListener {

            override fun onDataChange(dataSnapshot: DataSnapshot) {
                // For each loop will run until all notes are fetched
               for (snapshot in dataSnapshot.children){
                   val note = snapshot.getValue(Note::class.java)
                   Log.e("Note",note?.title)
               }
            }

            override fun onCancelled(databaseError: DatabaseError) {
                // On failed, log a message
                Log.e("Debug", "loadPost:onCancelled", databaseError.toException())
            }
        }

        //You can use the addListenerForSingleValueEvent() method to simplify this scenario: it triggers once and then does not trigger again.
        //ref.child(token) is the path for reach notes for each unique user , in your case it can be ref only
        ref.child(token).addListenerForSingleValueEvent(noteListener)

Leave a Reply

Your email address will not be published. Required fields are marked *