javaandroidfirebasefirebase-realtime-databaseandroid-studio-4.2

Firebase Realtime Database (Android-Java)- "Class does not define a no-argument constructor"


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:

  1. What I am doing wrong?
  2. How can I parse a JSON with multiple levels?
  3. Does the name of the variables must to be the same than the names of the keys of the JSON?

Thanks in advance!

JSON looks like this:

Data Tree

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.


Solution

  • 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;
    }
    

    }