I used to parse dataSnapshots using maps like this Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
But then when I was watching a tutorial on YouTube I saw the guy parsing the dataSnapshot using a class like this User user = dataSnapshot.getValue(User.class);
and now I have a lot of questions.
How does that work?
I mean what if the class User had different members than the snapshot would it give us an error?
For example
snapshot:
-User
|-Name:jojo
|-Age:19
User Class fields:
boolean a;
float x;
int c;
what if the fields of the class User where putter in a different order than the ones on the snapshot and with different capitalization or what if the class had one missing field?
Example for my second question:
snapshot:
-User
|-Name:jojo
|-Age:19
User Class fields:
int age;
String name;
I have read the firebase docs https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot#getValue(java.lang.Class) but it does not answer my two questions it just says the class must have an empty constructor and a getter for each field
EDIT:
snapshot:
-User
|-Followers
|-id:xxxxxx
|-id:xxxxxx
|-Name:jojo
|-Age:19
User Class fields:
int age;
String name;
CodePudding user response:
Firebase tries to map between the properties in the JSON data from the database and those in your class using JavaBean naming conventions. The simplest possible class to map to your data snapshot would be:
public static class User {
public String Name;
public long Age;
}
This class has a public field for each property in the database, and the compiler will generate a default, no-argument constructor, which is what Firebase needs in order to create User
objects for the data.
A more common patter is to create getters and/or setters for the properties. With all of those for both of your properties, you'd get:
public static class User {
String Name;
long Age;
public String getName() { return Name }
public void getName(String name) { Name = name }
public long getAge() { return Age }
public void setSage(long age) { Age = age }
}
Now with these the fields themselves no longer have to be public, and we can do extra work if needed in the get and set methods. But the name of the properties will now be determined from those getters and setters using JavaBean naming conversions, which leads to properties name
and age
with a different casing than what you have in the database.
To solve this, you can provide annotations in your code what the database properties for each field are:
public static class User {
String Name;
long Age;
@PropertyName("Name")
public String getName() { return Name }
@PropertyName("Name")
public void getName(String name) { Name = name }
@PropertyName("Age")
public long getAge() { return Age }
@PropertyName("Age")
public void setSage(long age) { Age = age }
}
Now the Firebase mapper will read the PropertyName
annotations and be able to correctly map between the data from the database and that in your objects again.
If your class has more properties (so either public fields or getters/setters) than the data from the database, those properties are left unpopulated when it reads data from the database. When writing to the database, the additional properties will be written to the database.
If you want to prevent this, you can use the @IgnoreExtraProperties
annotation.
Also see: