TruffelNL
TruffelNL

Reputation: 520

Firestore: (21.4.1) [CustomClassMapper]: No setter/field

I have a User class which saves some extra data on the user. This data is stored in/coming from Firestore. I have a couple of fields which are working(name, surname, lastLogin) but a couple of them are not working(blocked).

When I make the field public they work, but when I try to use a setter, it doesn't. I tried cleaning the build and rebuilding it. I know it is not saving the field due to @Exclude, that is intended.

What am I doing wrong? The field type doesn't matter, I've added a new String field which gave the same warning, while name and surname work.

The database:

**userid**
  {
    "name" : "John",
    "surname" : "Doe",
    "lastLogin" : **timestamp**,
    "blocked" : true
  }

The class:

@Keep
public class User
{
    private String name;
    private String surname;
    private Date lastLogin;
    private boolean blocked = false;

    public User()
    {
    }

public String getName()
{
    return name;
}

public void setName(String name)
{
    this.name = name;
}

public String getSurname()
{
    return surname;
}

public void setSurname(String surname)
{
    this.surname = surname;
}

public Date getLastLogin()
{
    return lastLogin;
}

public void setLastLogin(Date lastLogin)
{
    this.lastLogin = lastLogin;
}

@Exclude
public boolean isBlocked()
{
    return blocked;
}

public void setBlocked(boolean blocked)
{
    this.blocked = blocked;
}

Upvotes: 2

Views: 1280

Answers (3)

Hilmy S F
Hilmy S F

Reputation: 41

You can try to add @field:JvmField to your boolean variable inside your User class.

Upvotes: 0

Alex Mamo
Alex Mamo

Reputation: 138944

The problem in your code is that the constructor in the User class is private. That's not the correct way in which you should create a new instance of the class. JavaBeans require a no-argument constructor to be present.

When Cloud Firestore SDK deserializes objects that are coming from the database, it requires that any objects in use, to have this public no-argument constructor, so it can use it to instantiate the object. Fields in the objects are set by using public setter methods or direct access to public members, as you already tried.

Because your constructor is private, the SDK doesn't really know how to create an instance of it. So it is mandatory to change it as public. A correct way to create that class should be:

class User {
    private String name;
    private String surname;
    private long lastLogin;
    private boolean blocked = false;

    public User() {} //Needed for Cloud Firestore

    public User(String name, String surname, long lastLogin, boolean blocked) {
        this.name = name;
        this.surname = surname;
        this.lastLogin = lastLogin;
        this.blocked = blocked;
    }

    //Getters and setters are not mandatory
}

Also please note that the setters and the getters are not required. Setters are always optional because if there is no setter for a JSON property, the Firebase client will set the value directly onto the field.


Edit:

According to your comment:

but it does not explain why some fields are working and others aren't. It should not work at all, right?

Yes, that's right, all should work. The reason why some of them are not working is that the blocked property in your User class is of type boolean while in your database is of type String and this is not correct. Both types must match.

And the private constructor is due to the singleton instance, as far as I know, the constructor should be private to avoid creating new instances of the class.

No, the constructor must be public. I think there is a misunderstanding. Every time you use FirebaseDatabase.getInstance(), a single socket connection between your application and the Firebase servers is opened. From that moment on, all traffic between the application and the database goes over the same socket. So it doesn't matter how many times you create an instance, it will always be a single connection. Regarding your POJO class, there is no need for such a Singleton because Firebase always needs to know how to create an instance of that class, using the public no-argument constructor.

Upvotes: 2

Shimaa Yasser
Shimaa Yasser

Reputation: 627

Try to create a constructor with parameters for all class attributes along with a non-parameter constructor and then in the java class where you store in firebase, create object from user and pass it.

for example:

 package com.example.spacing.Model;

 public class User {

private String username;
private String phone;
private String id;
private String imageURL;

private String email;

public User(String username, String email ,String phone, String id, String imageURL) {
    this.username = username;
    this.email=email;
    this.phone = phone;
    this.id = id;
    this.imageURL = imageURL;
}

public String getImageURL() {
    return imageURL;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public User() {
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}
   }

and

FirebaseDatabase.getInstance().getReference("Users")

.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
                                .setValue(user);

Upvotes: 0

Related Questions