I am trying to read data from Firebase Realtime Database on a Java Android project. I am using Android Studio 4.2.2.
I can get the JSON string fine. The problems start when I try to deserialize the data.
At that point I get an exception: "does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped."
The point is that I have already defined a no-argument constructor. I have also checked the docs here https://firebase.google.com/docs/database/android/read-and-write
My questions are:
Thanks in advance!
JSON looks like this:
In Logcat I can see the JSON arrives safe to the app:
{ key = 1, value = {phone=123456789, name=Mike} }
Here there is the code:
public class DataBaseHelper {
private DatabaseReference mDatabase;
public TestData result;
public DataBaseHelper() {
mDatabase = FirebaseDatabase.getInstance().getReference();
// Creamos query
Query query = mDatabase.child("TestData");
query.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
try {
Log.w("datosdb", userSnapshot.toString());
result = userSnapshot.getValue(TestData.class);
} catch (Exception e) {
Log.w("datosdb", "Parse failed", e);
}
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w("datosdb", "loadPost:onCancelled", databaseError.toException());
// ...
}
});
}
public class TestData {
public TestData() {
}
public String name;
public int phone;
public String getName() {
return this.name;
}
public int getPhone() {
return this.phone;
}
}
}
Here is the exception:
2021-07-12 00:58:01.631 25262-25262/com.example.purinasa W/datosdb: DataSnapshot { key = 1, value = {phone=123456789, name=Mike} } 2021-07-12 00:58:01.637 25262-25262/com.example.purinasa W/datosdb: Parse failed com.google.firebase.database.DatabaseException: Class com.example.purinasa.application.dataBase.DataBaseHelper$TestData does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped. at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:570) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:563) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:433) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80) at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203) at com.example.purinasa.application.dataBase.DataBaseHelper$1.onDataChange(DataBaseHelper.java:33) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75) at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63) at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Update:
After doing some test with @Ticherhaz-FreePalestine we managed to deserialize the data individually using this lines:
String name = userSnapshot.child("name").getValue(String.class);
Log.w("datosdb", "String is here!!!" + name);
long phone = userSnapshot.child("phone").getValue(Long.class);
Log.w("datosdb", "Long is here!!!" + phone);
BTW, I cant find the way of using this another code without trowing an exception.
Finally it works by Using TestData as an independent class instead of an internal class. I made a new file TestData.java and moved its code there.
So finally DatabaseHelper loos like this:
public class DatabaseHelper {
private DatabaseReference mDatabase;
TestData result;
public DatabaseHelper() {
mDatabase = FirebaseDatabase.getInstance().getReference();
// We create a query
Query query = mDatabase.child("TestData");
//We recive query
query.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
Log.w("datosdb", "Tenemos el resultado de la query.");
try {
Log.w("datosdb", userSnapshot.toString());
// Deserializing only name
String name = userSnapshot.child("name").getValue(String.class);
Log.w("datosdb", "String is here!!!" + name);
// Deserializing only phone
long phone = userSnapshot.child("phone").getValue(Long.class);
Log.w("datosdb", "Long is here!!!" + phone);
// Deserializing into a TestData object
TestData result = userSnapshot.getValue(TestData.class);
Log.w("datosdb", "Parse success!!!");
} catch (Exception e) {
Log.w("datosdb", "Parse failed", e);
}
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w("datosdb", "loadPost:onCancelled", databaseError.toException());
// ...
}
});
}
}
And TestData looks like this (on its own .java file now):
public class TestData {
private String name;
private long phone;
public TestData(){}
public TestData(String name, long phone){
this.name = name;
this.phone = phone;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public long getPhone() {
return this.phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
}