3

I'm trying to get a list of users from Firebase, in Android.

enter image description here

I already have the uuid of the user, and using that I'm trying to get the entire object. The uuid is both the node name and a field inside the user node (identical, of course).

Here is my code:

DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("users");
Query query = usersRef.orderByChild("uuid").equalTo(animalMarker.getUserUid());
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            Log.d(TAG, "onDataChange: xxxxxxxx---- entered onDataChange");

            // go to node "users/userUID" , becuase dataSnapshot is parent node
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                Log.d(TAG, "xxxxxxxx---- onDataChange: ds= " + ds);
                User user = ds.getValue(User.class);
                Log.d(TAG, "xxxxxxxx---- onDataChange: user=" + user);
                // createdByTV.setText("Created by \n" + user.getEmail());
            }

        }

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

        }
    });

I dont know if the error "expected List but got HashMap" is coming from the entire DataSnapshot itself, or from the animals List inside the user ( The user class has a field List animals )

I've already checked this similar question Andorid-Expected a List while deserializing, but got a class java.util.HashMap and several others but I still can't understand what is wrong.

EDIT: I'm trying to get the user email, knowing it's ID(uuid). While getting the entire User object is not necessary, I'm curios as to how it would be done, since I can't manage to do either of these.

EDIT: here is my User class

public class User {

private String uuid;
private String email;
private String name;
private List<User> friends;
private List<Animal> animals;

public User() {
}

public User(String email, String name) {
    this.email = email;
    this.name = name;
}

public User(String uuid, String email, String name) {
    this.uuid = uuid;
    this.email = email;
    this.name = name;
}
... // getters and setters, toString and other such
}

When trying to get the User which doesn't have the animals node inside it, everything works fine. but when trying to get the user with the animals node inside, the app crashes.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Andy
  • 141
  • 3
  • 13

3 Answers3

8

Actually, I answered that question but in this case the problem is a little different. So you are getting the following error:

expected List but got HashMap

Because your animals node that exist within each user object is not a list of animal objects is actually a map of animal objects and that's why this error.

While getting the entire User object is not necessary, I'm curios as to how it would be done, since I can't manage to do either of these.

It's true, you can get the email address simply using the following line of code:

String email = ds.child("email").getValue(String.class);

Now, to map a DataSnapshot object to a User and get a list of animal objects from a particular user, please remove:

//private List<User> friends;
//private List<Animal> animals;

And use the following lines of code:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference animalsRef = rootRef.child("users").child(uid).child("animals");
ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        List<Animal> animalList = new ArrayList<>();
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            Animal animal = ds.getValue(Animal.class);
            animalList.add(animal);
        }

        //Do what you need to do with the animalList
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
    }
};
animalsRef.addListenerForSingleValueEvent(valueEventListener);
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hello, again! And thank you very much for your answer, it worked! In the end I changed the User object data from a List to a HashMap as a workaround. I didn't want to make another DatabaseReference and ValueEventListener, but instead retrieve the entire User object with it's animals. Your answer gave me more insight on working with Firebase Database, thank you. – Andy Apr 18 '19 at 10:14
0

The animals list is not inside the user, it is inside the users node. In any case making it inner to the user object seems to be more nested than needed. You should have another node for the animals

user_animals:{
    uid:{key1:{}, key2:{}
}

Your problem now is you are making a query instead of getting the node value

usersRef.child(uid).addSingleEvent..

...onDataChange...
User user = datasnapshot.getValue(User.class);

You need to create a User class that reflects your users attributes in the RTD

cutiko
  • 9,887
  • 3
  • 45
  • 59
  • I have. Using the first user which has no animals inside it, the app works fine. When fetching the other user however the app crashed. Should the Lists inside the User class be made HashMaps for it to work? I was under the impression that Firebase Realtime Database could get the custom object(Animal) from within another object(User). – Andy Apr 15 '19 at 18:57
  • The animals are not inside the user but inside the users node – cutiko Apr 15 '19 at 18:58
  • I'm sorry but I still don't understand. Wouldn't that node (named "animals" inside user) be a List, with each node inside it being an element of that List? – Andy Apr 15 '19 at 19:00
  • Your animals are not inside a single user but inside the users, your data is 1 user and 1 list of animals – cutiko Apr 15 '19 at 19:02
  • Sorry, I think I'm not understanding right. But my "animals" node is inside a user, and each user may have one(list). Isn't that the same as the class User ? The logic being that all the animals in a user's list belong to that user. – Andy Apr 15 '19 at 19:05
0

The way you build your tree is the root of the problem.

I had the same error just today while refactoring a firebase tree of an old project, so I looked for the error in google and found this page, and I notice this 3 user attributes inside your animal node that looked out of place.

So I went back to my tree and apprantly I had mistakenly added a key:value pair inside one of my list nodes, so I removed them and everything was fine.

The problem:

It is because you have a list of animals and inside that list you have this 3 key-values (email, uuid, name), this confuses firebase serilization so he tries to convert it into hashmap

The solution:

I think you will benefit in the future if you don't work around it and do as follows: the 3 user attributes email, name and uuid should be wrapped inside a different node inside the user tree, something like user_data and you should have a different node for animals that will have only the animal list!

  • users
    • sfdasfasfasfasf
      • user_data
        • email:"asdf"
        • name:"asdfas"
        • uuid:"dfqwtr4"
      • animals
        • asdfaskdfjlasdgafd
          • adult:"asdf"
          • animalId:"asdfas"
          • animalName:"dfqwtr
          • approxAge:"asdf"
          • neutred:"asdfas"
          • photoLink:"dfqwtr"
        • sdafasfdasgasga
          • adult:"asdf"
          • animalId:"asdfas"
          • animalName:"dfqwtr
          • approxAge:"asdf"
          • neutred:"asdfas"
          • photoLink:"dfqwtr"

Then your pojo's should look something like: a User class with properties of a UserData and List<Animal> with the corresponding names for serilization.

Danny
  • 345
  • 1
  • 4
  • 11