Ad

Android: Firestore Fails With "Found Conflicting Setters With Name: SetWallpaper"

- 1 answer

Don't be quick to judge based on the title alone, I know similar questions have been asked before but this problem is a little different. Please bear with me and read through.

So I have defined a BaseUser class as follows:

import android.support.annotation.NonNull;
import android.util.Log;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.Exclude;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.storage.FirebaseStorage;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class BaseUser
{
    private static final String TAG = "BaseUser";

    /**
     * Firebase Authentication and Database
     */
    protected FirebaseAuth auth;
    protected FirebaseFirestore db;
    protected FirebaseStorage st;

    /**
     * General BaseUser Info
     */
    private String firstName;
    private String lastName;
    private List<String> phones;
    private List<String> emails;
    private List<AddressLocation> addresses;

    public BaseUser()
    {
        auth = FirebaseAuth.getInstance();
        db = FirebaseFirestore.getInstance();
        st = FirebaseStorage.getInstance();
        phones = new ArrayList<>();
        emails = new ArrayList<>();
        addresses = new ArrayList<>();
    }

    /**
     * Getters
     */

    public final String getFirstName()
    {
        return firstName;
    }

    public final String getLastName()
    {
        return lastName;
    }

    @Exclude
    public final List<String> getPhones()
    {
        return phones;
    }

    @Exclude
    public final List<String> getEmails()
    {
        return emails;
    }

    @Exclude
    public final List<AddressLocation> getAddresses()
    {
        return addresses;
    }

    /**
     * Special Getters
     */

    @Exclude
    public final String getPhone(int index)
    {
        return phones.get(index);
    }

    // SimilarStuff


    /**
     * Setters
     */

    @Exclude
    public final void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    @Exclude
    public final void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    @Exclude
    public final void setPhones(List<String> phones)
    {
        this.phones = phones;
    }

    @Exclude
    public final void setEmails(List<String> emails)
    {
        this.emails = emails;
    }

    @Exclude
    public final void setAddresses(List<AddressLocation> addresses)
    {
        this.addresses = addresses;
    }

    /**
     * Special Setters
     */

    @Exclude
    public final void addPhone(String phone)
    {
        this.phones.add(phone);
    }

    // SimilarStuff

    /**
     * Authentication
     */
    @Exclude
    public final boolean isLoggedIn()
    {
        assert(auth != null);
        return (auth.getCurrentUser() != null);
    }

    /**
     * Shared BaseUser Instance
     */

    protected static BaseUser holder = new BaseUser();

    @Exclude
    public static BaseUser getInstance()
    {
        assert(holder != null);
        return holder;
    }

    /**
     * Database
     */

    @Exclude
    protected final void downloadUser(final Callable<Void> callback)
    {
        // Doesn't get called for now.
    }

    @Exclude
    protected final void uploadUser()
    {
        assert(isLoggedIn());
        db.collection("users").document(auth.getCurrentUser().getUid()).set(this).addOnFailureListener(new OnFailureListener()
        {
            @Override
            public void onFailure(@NonNull Exception e)
            {
                Log.wtf(TAG, "Failed to write user data");
            }
        });
    }
}

as you can see, the class defines a couple of strings along with a couple of Arrays. And includes absolutely nothing else that might have setWallpaper. Also, as you can see, as an effort to locate the source of the error I've literally excluded all functions (yes, even if they do not start by set or get) except for the two functions that read the two simple strings.

Now when the uploadUser method gets called I get the following error:

java.lang.RuntimeException: Found conflicting setters with name: setWallpaper (conflicts with setWallpaper defined on android.content.ContextWrapper)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.<init>(com.google.firebase:[email protected]@18.0.0:632)
        at com.google.firebase.firestore.util.CustomClassMapper.loadOrCreateBeanMapperForClass(com.google.firebase:[email protected]@18.0.0:348)
        at com.google.firebase.firestore.util.CustomClassMapper.serialize(com.google.firebase:[email protected]@18.0.0:169)
        at com.google.firebase.firestore.util.CustomClassMapper.access$300(com.google.firebase:[email protected]@18.0.0:53)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.serialize(com.google.firebase:[email protected]@18.0.0:774)
        at com.google.firebase.firestore.util.CustomClassMapper.serialize(com.google.firebase:[email protected]@18.0.0:170)
        at com.google.firebase.firestore.util.CustomClassMapper.access$300(com.google.firebase:[email protected]@18.0.0:53)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.serialize(com.google.firebase:[email protected]@18.0.0:774)
        at com.google.firebase.firestore.util.CustomClassMapper.serialize(com.google.firebase:[email protected]@18.0.0:170)
        at com.google.firebase.firestore.util.CustomClassMapper.access$300(com.google.firebase:[email protected]@18.0.0:53)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.serialize(com.google.firebase:[email protected]@18.0.0:774)
        at com.google.firebase.firestore.util.CustomClassMapper.serialize(com.google.firebase:[email protected]@18.0.0:170)
        at com.google.firebase.firestore.util.CustomClassMapper.serialize(com.google.firebase:[email protected]@18.0.0:101)
        at com.google.firebase.firestore.util.CustomClassMapper.convertToPlainJavaTypes(com.google.firebase:[email protected]@18.0.0:77)
        at com.google.firebase.firestore.UserDataConverter.convertAndParseDocumentData(com.google.firebase:[email protected]@18.0.0:216)
        at com.google.firebase.firestore.UserDataConverter.parseSetData(com.google.firebase:[email protected]@18.0.0:75)
        at com.google.firebase.firestore.DocumentReference.set(com.google.firebase:[email protected]@18.0.0:174)
        at com.google.firebase.firestore.DocumentReference.set(com.google.firebase:[email protected]@18.0.0:153)
        at com.companyname.projectname.authentication.SignupActivity$6$1$1.onComplete(SignupActivity.java:297)
        at com.google.android.gms.tasks.zzj.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6718)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

I grepped my folder to find out what includes setWallpaper and I found the following:

shell$ grep -rnw "setWallpaper" .
Binary file ./authentication/build/intermediates/transforms/instantRun/AppName/debug/0/com/companyname/projectname/authentication/ResetPasswordActivity.class matches
Binary file ./authentication/build/intermediates/transforms/instantRun/AppName/debug/0/com/companyname/projectname/authentication/WelcomeActivity.class matches
Binary file ./authentication/build/intermediates/transforms/instantRun/AppName/debug/0/com/companyname/projectname/authentication/SignupActivity.class matches
Binary file ./authentication/build/intermediates/transforms/instantRun/AppName/debug/0/com/companyname/projectname/authentication/LoginActivity.class matches
Binary file ./authentication/build/intermediates/transforms/instantRun/AppName/debug/0/com/companyname/projectname/authentication/PhoneVerificationActivity.class matches
Binary file ./authentication/build/intermediates/transforms/dexBuilder/AppName/debug/265/com/companyname/projectname/authentication/LoginActivity.dex matches
Binary file ./authentication/build/intermediates/transforms/dexBuilder/AppName/debug/265/com/companyname/projectname/authentication/WelcomeActivity.dex matches
Binary file ./authentication/build/intermediates/transforms/dexBuilder/AppName/debug/265/com/companyname/projectname/authentication/PhoneVerificationActivity.dex matches
Binary file ./authentication/build/intermediates/transforms/dexBuilder/AppName/debug/265/com/companyname/projectname/authentication/ResetPasswordActivity.dex matches
Binary file ./authentication/build/intermediates/transforms/dexBuilder/AppName/debug/265/com/companyname/projectname/authentication/SignupActivity.dex matches
Binary file ./authentication/build/intermediates/transforms/dexMerger/AppName/debug/1/classes.dex matches

So BaseUser has absolutely nothing to do with this setWallpaper thing. It's only related to my UI Activities (and I do not explicitly use it anyway).

What I've tried:

  1. Excluding everything except for 2 setters for simple Strings, as mentioned above.
  2. I thought maybe having the BaseUser class itself deal with Firestore is causing problems, so I tried doing the same from outside the class. Same.
  3. I tried Firebase Database rather than Firestore. Same.
  4. There're other classes that inherit BaseUser. I've disabled all of them. Same. (I'm not even sure why that would be a problem!)

Extra Info

I'm not sure if the following is relevant, but considering the weird nature of the error, I'm just going to throw it here anyway.

The class BaseUser is in a separate module called user. The UI classes that deal with authentication (and listed in the grep output above) are in a separate module called authentication. A third module core defines the firebase library dependencies and the necessary info from google-services.json.

I must also mention that with this configuration of modules I can use Firebase Authentication just fine. Only Firestore or Firebase Database have issues.

Question

Now why on earth is Firestore complaining about a setter that's not even in my class? How do I fix this?

Edit 1

I tried two different things now:

I tried uploading a simple map instead, so inside the uploadUser function I added the following:

protected final void uploadUser()
{
    assert(isLoggedIn());
    Map<String, Object> city = new HashMap<>();
    city.put("name", "Los Angeles");
    city.put("state", "CA");
    city.put("country", "USA");
    db.collection("users").document(auth.getCurrentUser().getUid()).set(city);
}

Which worked fine, Then I tried adding a simple class as the object to upload. as follows:

protected final void uploadUser()
{
    class Stupid {
        public String name;
        public String email;

        public Stupid()
        {
        }

        public Stupid(String name, String email)
        {
            this.name = name;
            this.email = email;
        }

        public String getName()
        {
            return name;
        }

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

        public String getEmail()
        {
            return email;
        }

        public void setEmail(String email)
        {
            this.email = email;
        }
    }
    Stupid stupid = new Stupid("Name", "Email");
    db.collection("users").document(auth.getCurrentUser().getUid()).set(stupid);
}

Which again, gave me the same error with setWallpaper. I also tried another variant of the Stupid class with ints rather than strings. Also same. A stupid simple POJO class. What is wrong with this whole thing?! I used to use classes and objects with Firebase database all the time before. What am I missing in this case?

Ad

Answer

Ok, so I did two things, not sure which of them fixed it (maybe both?!)

Previously, I was checking for google play services availability. So, for that, I included com.google.android.gms:play-services-base:16.1.0. Which caused me to get the error Error: Cannot fit requested classes in a single dex file. Try supplying a main-dex list. # methods: 72477 > 65536. My solution was to add multiDexEnable 'true'. What I did now was follow this answer instead. So I removed all the multi dex stuff and used com.google.android.gms:play-services-gcm:16.0.0 instead.

The second thing I did was disable instant run.

Now, the same code I have works like a charm and is able to read/write in Firestore.

I do not have any explanation for what was going on. But the problem is now gone.

Ad
source: stackoverflow.com
Ad