I know how to parse a simple DataSnapshot object to any Java class using public T getValue (Class<T> valueType). But after the Firebase 3.0 I am not able to parse the following data to my Java Class, as it contains a custom type instance for which I'm receiving NULL.
NOTE: The same logic was working fine before Firebase 3.0. I suppose its because now Firebase is using GSON instead of JACKSON. Please correct me if I'm wrong
DATA:
{
"address" : "DHA karachi",
"addresstitle" : "DHA karachi",
"logoimage" : {
"bucketname" : "test2pwow",
"id" : "zubairgroup",
"mediaType" : "image/png",
"source" : 1,
"url" : "https://pwowgroupimg.s3.amazonaws.com/zubairgroup1173.png?random=727"
},
"title" : "zubairghori"
}
Group.java
public class Group {
public String address;
public String addresstitle;
public LogoImage logoimage;
public Group(){}
}
LogoImage.java
public class LogoImage {
public String bucketname;
public String id;
public LogoImage(){}
}
Code that read:
Group group = datasnapshot.getValue(Group.class);
It doesn't cast LogoImage part of the database into the logoimage object. We always retrieve null in the logoimage object.
public T getValue(Class valueType)
1.The class must have a default constructor that takes no arguments
2.The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized
Check it from:
this source It'll help you
detail
I'm not sure why that is causing problem for you. This code works fine for me with the data you provided:
DatabaseReference ref = database.getReference("37830692");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Group group = dataSnapshot.getValue(Group.class);
System.out.println(group);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I had the same problem. I solved it by providing not only getters for all the values, but setter too. Hope this helps.
I had the same problem and solved it by making sure that the arguments of the constructor are spelled the same than the elements saved at Firebase. My mistake was that I was setting the key of Firebase with Uppercase letters and object arguments with lowercase letters.
Related
I need to return a data from Firebase to a Java Object, but even using an Interface, it always returns me null. Some help?
I created a "Coordinate" object inside the method and I'm trying to access the data like this: readData(value -> coordinates = value , offer);
public interface CoordinatesCallback {
void onCallBack(Coordinates value);
}
public void readData(CoordinatesCallback callback, Offer offer) {
String storeId = Integer.toString(offer.getStore().getId());
mDatabase.child("stores").child(storeId).child("coordinates").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Coordinates coordinates = dataSnapshot.getValue(Coordinates.class);
callback.onCallBack(coordinates);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
That's not how getValue() works. You have to pass it the Class object of a Java POJO with getters and setters for each field of the database you want to read. From the linked Javadoc:
This method is used to marshall the data contained in this snapshot
into a class of your choosing. The class must fit 2 simple
constraints:
The class must have a default constructor that takes no arguments
The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their
default value when an instance is deserialized
Hi all I can't think of a better example to illustrate my point so do let me know If my example has some errors. But hopefully this example will get my point through.
class A {
String CATEGORY = "A";
public String getCATEGORY() {
return CATEGORY;
}
}
class B extends A {
String CATEGORY = "B";
#Override
public String getCATEGORY() {
return CATEGORY;
}
}
class C extends A {
String CATEGORY = "C";
#Override
public String getCATEGORY() {
return CATEGORY;
}
}
public class MyClass {
private List<A> array = Arrays.asList(new A(), new B(), new C());
public MyClass() {}
}
Now if I upload MyClass onto firebase using setValue for example, firebase will show me the properties of class A, B and C. However, when I read the data from firebase and call sth like getValue(MyClass.class) the List it returns me are all of type A and the subclasses are not preserved. Is there a workaround to allow firebase to preserve the class types uploaded?
If you use Firebase's default serializer, it simply writes all public properties and fields to the database. Say that you store a single instance of each class, it'd be:
-L1234567890: {
cATEGORY: "A"
},
-L1234567891: {
cATEGORY: "B"
},
-L1234567892: {
cATEGORY: "C"
},
There won't be enough knowledge in the database for the SDK to reinflate the correct sub-class. While you and I can see that the cATEGORY value matches the class name, the Firebase SDK has no such knowledge.
It won't be too hard to write your own custom deserializer for this data though, taking a DataSnapshot with the values above and reinflating the correct class and values.
You could also do a hybrid: detect the class type directly, and then tell Firebase what class to read:
String cat = snapshot.child("cATEGORY").getValue(String.class)
Class clazz = "C".equals(cat) ? C.class : "B".equals(cat) ? B.class : A.clas;
A object = snapshot.getValue(clazz);
I have an existing array that I created locally and import to Firebase and my array looks like this.
These both elements are objects created that have some many information related to appointments.
Now i am trying to create a new element with the same form, for example:
2--
|__ And the object I have created in my app
I have only managed or eliminate the rest of the elements (with setValue(object))
Appointment newAppointment = new Appointment.Builder()
.fechacita(dateSelected)
.horacita(hourSelected)
.usertoken(mAuthManager.getCurrentUserId())
.oficina(centerSelected)
.build();
mDatabaseRef.child("LISTACITAS").setValue(newAppointment);
or create it with an ID that when recovering the data causes a crash in the application due to the deserialization of the objects that are not equal.
The Appointment object that I want to insert is
public class Appointment implements Parcelable {
private String fechacita;
private String horacita;
private Office oficina;
private String userID;
.....
}
The class is a normal Parcelable class that generates an object with her builder.
Please some help...
try this code
mDatabaseRef.push().setValue(incidentReportUser)
Write it this way (push() adds values instead of overriding).
Ans from here
UPDATE 1
if you want a series in key, not some random value, try this:
get the last key in the list using
Query dbQry = mDatabaseRef.orderByKey().limitToLast(1);
dbQry.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int key = Integer.parseInt(dataSnapshot.getKey());
//Increment the key and add the object here using the earlier method
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
I have not checked this as of now, but you could get the idea
I have a model class to store Firebase User information. Inside of the model class I have a HashMap to store all of the data inside. Once I have stored the data, the I push the Hashmap into the Firebase database. The values store fine, but I cannot access the values. Every time I try to access them, I get an error saying that I am attempting to invoke a virtual method on a null object reference.
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
// These two lines of code give the error.
User author = ChildSnapshot.child("profile").getValue(User.class);
String author_username = author.getUsername();
These give me the error. I am attempting to grab data from the child of the snapshot. Why is this giving me an error? Is there a better way to do this?
JSON Firebase snapshot:
Model class:
//TODO model class for the user. This way I can set the values for each user. I will be adding more values in the future.
public class User {
public HashMap<String, String> hashMap = new HashMap<String,String>();
public User() {
}
public User(String username) {
hashMap.put("username",username);
}
public String getUsername(){
return hashMap.get("username");
}
}
In case somebody else was struggling with this issue, I wanted to give an answer. Inside of my ChildEventListener, the profile is the key in this situation so when I use ChildSnapshot.child("profile").getValue(User.class) it returns a null value. Also, (I'm not quite sure why this is) the value of the username was stored in a different class called User_message which was used to store the message. so my updated code looks something like this:
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
User_message author = ChildSnapshot.getValue(User_message.class);
String author_username = author.getUsername();
I was facing the same problem and spent more than 5 hours. I added Default Constructor of the model and this solves my problem.
public class User {
public String email;
public String name;
public User() {
}
public User(String email, String name) {
this.email = email;
this.name = name;
}}
I hope this will help you. Thanks
I am implementing Firebase Recyclerview UI in my application. I have implemented a recyclerview adapter and it shows me following exception.
Following is my adapter code :
FirebaseRecyclerAdapter<DataSnapshot, MyHolder> recyclerAdapter = new FirebaseRecyclerAdapter<DataSnapshot, MyHolder>(
DataSnapshot.class,
R.layout.row_slots,
MyHolder.class,
databaseReference.child("slots").child(uid).child(dayOfWeek).child("time")
) {
#Override
protected void populateViewHolder(MyHolder viewHolder, DataSnapshot model, int position) {
System.out.println("Key : "+model.getKey());
}
};
It is showing following exception :
How can I get a snapshot value using FirebaseRecyclerAdapter?
The problem is DataSnapShot is missing a no Argument Constructor so you can not use it directly like this.
Use some other model class instead.
Like this :
Create your own model called FriendlyMessage :
public class FriendlyMessage {
private String text;
private String name;
// Created constructor with no Arguments
public FriendlyMessage() {
}
public FriendlyMessage(String text, String name) {
this.text = text;
this.name = name;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Most important thing we have created constructor with no Arguments
which was missing in DataSnapShot
NOTE : The above model class is just an example for you as you are new in firebase. You can have your own model class with your own type of parameters and all.
The use it like this for your Firebase Recyclerview :
FirebaseRecyclerAdapter mFirebaseAdapter = new FirebaseRecyclerAdapter<FriendlyMessage, MyHolder>(
FriendlyMessage.class,
R.layout.row_slots,
MyHolder.class,
databaseReference.child("slots").child(uid).child(dayOfWeek).child("time")) {
#Override
protected void populateViewHolder(MyHolder viewHolder, FriendlyMessage friendlyMessage, int position)
{
}
};
EDIT :
It also matter how you are pushing the data on Database. Do it
directly with your model class.
For example for above model FriendlyMessage push it like this :
FriendlyMessage friendlyMessage = new FriendlyMessage("message", "Username");
databaseReference.child(MESSAGES_CHILD).push().setValue(friendlyMessage);
Here your child() will be somewhat different from my implementation it is just an example.
For Listening to a particular DataSnapShot :
databaseReference.child("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
//The PUSH ID OP WANTED
System.out.println("Push Id ---"+postSnapshot.getKey());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
})
Explaining the above listener. It will give you the DataSnapShot
Object for your every user who is falling inside your child "users". You can access Push id by getKey() method.
firebaser (and author of the FirebaseUI adapters) here
Lots of good answers already. I'd indeed typically recommend creating a Java class that represents your data objects.
But if you're intent on using a DataSnapshot, you can override FirebaseRecyclerAdapter.parseSnapshot to handle the "conversion":
#Override
protected ChatMessage parseSnapshot(DataSnapshot snapshot) {
return snapshot;
}
When initializing your recyclerAdapter, your passing a DataSnapshot.class as your modelClass, wherein a DataSnapshot doesn't really have a Constructor with no parameters which I think is causing the error, also I think that makes a DataSnapshot an invalid modelClass.
As stated in the FirebaseRecyclerViewAdapter for the modelClass:
modelClass - Firebase will marshall the data at a location into an instance of a class that you provide
You should define your own modelClass by creating an object that suites your needs. There's a simple example on the FirebaseRecyclerViewAdapter link that you can check out. Cheers!
EDIT:
As per the comments, I suggested to have your own modelClass object have a DataSnapshot as a parameter. For a simple example of what I'm saying, refer below.
public class ModelClass {
String sampleString;
ModelClass() {
}
ModelClass(DataSnapshot dataSnapshot) {
// Do what you need from the dataSnapshot here
sampleString = dataSnapshot.child("").toString();
}
}
I think from the example above, you would get what I mean. BUT, I'm not sure if this is recommended nor if it's even acceptable. I haven't tried this out before so I'm also not sure if it'll work.
Since this concern is actually different from the one posted. I suggest posting a different one if ever it doesn't work. Happy Coding. Cheers!