10

I am getting following exception while updating an existing value in the Firebase using updateChildren method.

com.firebase.client.FirebaseException: Failed to parse node with class class com.shajeelafzal.quicktasks_app.models.HashTagModel
  at com.firebase.client.snapshot.NodeUtilities.NodeFromJSON(NodeUtilities.java:84)
  at com.firebase.client.snapshot.NodeUtilities.NodeFromJSON(NodeUtilities.java:12)
  at com.firebase.client.utilities.Validation.parseAndValidateUpdate(Validation.java:127)
  at com.firebase.client.Firebase.updateChildren(Firebase.java:438)
  at com.shajeelafzal.quicktasks_app.fragments.AddEditTaskFragment$4.onDataChange(AddEditTaskFragment.java:408)

My model looks like this:

public class HashTagModel implements Parcelable {

    private HashMap<String, Object> timeStampLastUsed;
    @Expose
    private String name;
    @Expose
    private String createByUserEmail;
    private List<String> tasksKeys;

    public HashTagModel() {
    }

    public HashTagModel(HashMap<String, Object> timeStampLastUsed, String name,
                        String createByUserEmail, ArrayList<String> tasksKeys) {
        this.timeStampLastUsed = timeStampLastUsed;
        this.name = name;
        this.createByUserEmail = createByUserEmail;
        this.tasksKeys = tasksKeys;
    }
}

JSON Object that I want to update looks like this on Firebase:

"hashTags" : {
    "USER_EMAIL" : {
      "USA" : {
        "createByUserEmail" : "USER_EMAIL",
        "name" : "#USA",
        "tasksKeys" : [ "-K6mS36uhKthKf1-1pF1" ],
        "timeStampLastUsed" : {
          "timestamp" : 1451514461234
        }
      }
    }
  }

And my onDateChange method looks like this:

public void onDataChange(DataSnapshot dataSnapshot) {
    /** if the hash tag does not exists already then create new one. */
    if (dataSnapshot.getValue() == null) {
        HashMap<String, Object> timestampJoined = new HashMap<>();
        timestampJoined.put(Constants.FIREBASE_PROPERTY_TIMESTAMP, ServerValue.TIMESTAMP);

        ArrayList<String> keysList = new ArrayList<String>();
        keysList.add(key);

        HashTagModel hashTag = new HashTagModel(timestampJoined, "#" + mHashTags.get(finalI),
                Utils.decodeEmail(mEncodedEmail), keysList);
        finalHashTagLocation.setValue(hashTag);
    } else {

        HashTagModel hashtaghModel = dataSnapshot.getValue(HashTagModel.class);

        hashtaghModel.getTasksKeys().add(key);

        /* HashMap for data to update */
        HashMap<String, Object> updateUserTaskData = new HashMap<>();


        Utils.updateMapForAllWithValue(null, mHashTags.get(finalI), mEncodedEmail,
                updateUserTaskData, "", hashtaghModel, Constants.FIREBASE_LOCATION_USER_HASH_TAGS);


        /** update the Hash Tag */
        finalHashTagLocation.updateChildren(updateUserTaskData, new Firebase.CompletionListener() {
            @Override
            public void onComplete(FirebaseError firebaseError, Firebase firebase) {
                Log.i("", "");
            }
        });
    }

    getActivity().finish();
}
Shajeel Afzal
  • 5,913
  • 6
  • 43
  • 70
  • Please include the actual JSON text from you Firebase database. You can get it by clicking the Export button in the Firebase dashboard and it will allow us to copy/paste the JSON for testing (or into an answer). – Frank van Puffelen Dec 30 '15 at 22:54
  • @FrankvanPuffelen i added the JSON text. – Shajeel Afzal Dec 30 '15 at 22:59
  • Thanks. We're also missing the code that writes to Firebase (in `onDataChange()`). And is the `HashTagModel` class really needed (and does it need to be this big) to reproduce the problem? – Frank van Puffelen Dec 30 '15 at 23:01
  • @FrankvanPuffelen i can remove the Parcelable code. I thought i might help to understand. I am adding the code that is supposed to update. – Shajeel Afzal Dec 30 '15 at 23:03
  • I'm pretty sure you're being affected by the same problem as described here: http://stackoverflow.com/questions/32848024/android-firebase-2-4-illegalstateexception-using-new-ref-updatechildren. You cannot pass Java classes into `updateChildren()`. My answer on that question has a workaround for this. – Frank van Puffelen Dec 31 '15 at 05:44

1 Answers1

15

Unlike the setValue() method, updateChildren() does not perform a Java-to-JSON conversion on the value(s) you pass in.

You're passing a HashMap<String, Object> into updateChildren(), which fits the contract of that API. But I'm pretty sure in some of the values you have a Java object (likely a HashTagModel) that is not directly mapped to a JSON type.

But what you can do is convert the POJO into a Map with:

Map<String, Object> hashtaghMap = new ObjectMapper().convertValue(hashtaghModel, Map.class);

Then you can put the map of values into the values that you're passing into updateChildren().

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks @FrankvanPuffelen – srinivas Feb 04 '16 at 06:04
  • @FrankvanPuffelen what about now that jackson is no more used by FirebaseDatabase? Should we import it as a dependency to achieve the same result? I'd rather not, since from what I read one of the reason of its removal was a concern for the final apk size. (Ref. http://stackoverflow.com/questions/37335712/android-firebase-9-0-0-setvalue-to-serialize-enums) – Ena Jul 09 '16 at 21:07
  • If you find a need that our new serialization/deserialization doesn't handle, you can use Jackson. See [this answer](http://stackoverflow.com/questions/37547399/how-to-deserialise-a-subclass-in-firebase-using-getvaluesubclass-class/37548330#37548330) for how to do that. And don't forget to also let us know about your use-case, so that we can consider adding support for it. – Frank van Puffelen Jul 09 '16 at 23:35
  • 1
    @FrankvanPuffelen thanks for the quick reply. My use case is the very same of this answer: to use updateChildren without the need to convert the pojo to a map manually. You suggested to use ObjectMapper but it is a Jackson class, so I was wondering if we can achieve the same result with the FirebaseDatabase API. Am I missing something? (And please forgive my ignorance, why updateChidren doesn't allow pojos as setValue does? If it is feasable to have a corresponding method that allows pojos, I would ask support for it instead :) ) – Ena Jul 10 '16 at 13:43
  • @FrankvanPuffelen I'm also backing up @Ena's question from above. Is there any way to use `updateChildren` without manually converting objects to maps? – Cosmin SD Mar 14 '17 at 23:02