0

I have a Race object which has a randomArticlesPair property. This property is initialised to be null . This is how this object's document looks like in the database:

enter image description here

I'd like to set the randomArticlesPair property later and put a custom object instead, and this is how I do it:

CollectionReference usersRef= FirebaseFirestore.getInstance().collection(FirebaseConstants.USERS);
DocumentReference senderRef=usersRef.document(raceRoom.getSenderEmail()).collection(FirebaseConstants.RACES_FEED).document(raceRoomID);

Map<String,Object> randomArticlesPair=new HashMap<>();
randomArticlesPair.put(FirebaseConstants.RANDOM_ARTICLES_PAIR,raceRoom.getRandomArticlesPair());

senderRef.set(randomArticlesPair,SetOptions.merge());

This is the RandomArticlePair object that I'm trying to insert:

public class RandomArticlesPair {

    private RandomArticle randomArticleA;
    private  RandomArticle randomArticleB;

    public RandomArticlesPair(){}

    public RandomArticlesPair(RandomArticle randomArticleA, RandomArticle randomArticleB) {
        this.randomArticleA = randomArticleA;
        this.randomArticleB = randomArticleB;
    }

    public RandomArticle getRandomArticleA() {
        return randomArticleA;
    }

    public RandomArticle getRandomArticleB() {
        return randomArticleB;
    }
}

Its properties are two RandomArticle objects:

@IgnoreExtraProperties
public class RandomArticle {
    private String title, firstParagraph, id, url;
    @Exclude private List<Linkshere>backTemplates_List;
    @Exclude private List<Backlink>backlinks_List;

    public RandomArticle(){}

    public RandomArticle(String title, String firstParagraph, String id, String fullUrl){
        this.title=title;
        this.firstParagraph=firstParagraph;
        this.id=id;
        this.url=fullUrl;
    }

    public RandomArticle(String title, String fullUrl){
        this.title=title;
        this.url=fullUrl;
    }

    public RandomArticle(String title, String firstParagraph, String id, String fullUrl, List<Linkshere>backTemplates_List){
        this.title=title;
        this.firstParagraph=firstParagraph;
        this.id=id;
        this.url=fullUrl;
        this.backTemplates_List=backTemplates_List;

    }

    public String getTitle(){
        return this.title;
    }

    public String getFirstParagraph(){
        return this.firstParagraph;
    }

    public String getId(){
        return this.id;
    }

    public String getURL(){
        return this.url;
    }

    @Exclude public List<Linkshere> getBacktemplatesList(){
        return this.backTemplates_List;
    }

    @Exclude public void setBacklinks_List(List<Backlink> backlinks_List) {
        this.backlinks_List = backlinks_List;
    }

    @Exclude public List<Backlink> getBacklinksList(){
        return this.backlinks_List;
    }

}

My problem is that after trying to add the new data, I'm getting this error:

05-06 22:59:17.313 2991-2991/com... E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com..., PID: 2991
    java.lang.IllegalArgumentException: Invalid data. Unsupported type: com....infrastructure.objects.random_article.RandomArticlesPair (found in field randomArticlesPair)
        at com.google.firebase.firestore.UserDataConverter$zza.zzb(SourceFile:232)
        at com.google.firebase.firestore.UserDataConverter.zzb(SourceFile:578)
        at com.google.firebase.firestore.UserDataConverter.zza(SourceFile:452)
        at com.google.firebase.firestore.UserDataConverter.zza(SourceFile:479)
        at com.google.firebase.firestore.UserDataConverter.zza(SourceFile:445)
        at com.google.firebase.firestore.UserDataConverter.parseMergeData(SourceFile:275)
        at com.google.firebase.firestore.DocumentReference.set(SourceFile:149)
        at com....multiplayer.races.RaceActivity_Sender$6.onDataChange(RaceActivity_Sender.java:199)
        at com.google.firebase.database.zzp.onDataChange(Unknown Source:7)
        at com.google.android.gms.internal.firebase_database.zzfc.zza(Unknown Source:13)
        at com.google.android.gms.internal.firebase_database.zzgx.zzdr(Unknown Source:2)
        at com.google.android.gms.internal.firebase_database.zzhd.run(Unknown Source:71)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Inserting a string works just fine:

randomArticlesPair.put(FirebaseConstants.RANDOM_ARTICLES_PAIR,"plain old string");

enter image description here


How can I fix this?

12
  • I don't understand what you mean by "It happened with every object I've tried to set instead of this null value." Commented May 6, 2018 at 17:38
  • @DougStevenson I have edited my question. I hope it's clearer. Commented May 6, 2018 at 17:50
  • What if you just try to put a plain old string? Commented May 6, 2018 at 18:26
  • what is that doc type?plus what you need to do is to update children not set value Commented May 6, 2018 at 19:17
  • @DougStevenson Inserting a string works just fine. Commented May 6, 2018 at 19:17

1 Answer 1

1

Generally, the expectation is that you'd use POJOs or maps of primitive types, but not intermix them. In this particular case, since you already have a Race object, I think you could just write it directly, and then update it again later. Something like this:

Race race = createRaceObjectWithNullRandomArticlesPair();
senderRef.set(race);
...
race.setRandomArticlesPair(...);
senderRef.set(race, SetOptions.merge());

Would that work for your situation?


The difficulty in allowing maps of POJOs is that it isn't clear how they should be extracted, and we're trying to avoid an asymmetry between reads/writes, as we think it'll lead to more confusion in the long term.

For instance, you could pass in Map.class to the DocumentSnapshot.toObject() method, but due to java's type erasure, it would be difficult to specify that you want a map of strings to RandomArticlesPair objects. (Though it's not actually impossible. You could use an approach like the one described here: http://gafter.blogspot.ca/2006/12/super-type-tokens.html but that's getting a bit off-topic, since Firestore doesn't currently support anything like that.)

Sign up to request clarification or add additional context in comments.

2 Comments

Your approach works for me. However, its downside is that it forces me to move around the "parent" object and not just its properties (the nested objects), which I already have in the current activity.
@TalBarda There is one other option, though I'm a little hesitant to point it out, as it's kinda kludgy and not supported. So I'll hide it down here in the comments. :) You could cast your map to an Object. This will cause Firestore to treat the map itself, and everything inside it, as a POJO. i.e. instead of this: senderRef.set(randomArticlesPair,SetOptions.merge()); do this: senderRef.set((Object)randomArticlesPair,SetOptions.merge()); The difficulty is that it isn't possible to extract this in the same way, so this may lead to headaches down the road.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.