Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenericTypeIndicator missing from firestore library but required #222

Open
mrsylerpowers opened this issue Jan 30, 2019 · 8 comments
Open
Labels

Comments

@mrsylerpowers
Copy link

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: 3.2.1
  • Firebase Component: firestore
  • Component version: 17.1.5

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

What Happened:
When you try to retrieve a object and turn it to a object with a generic with type parameters EX( a Map/HashMap) you get the error Could not deserialize object. Class java.util.HashMap has generic type parameters, please use GenericTypeIndicator instead
What would normally happen is using GenericTypeIndicator to define the types but that class isn't included with the firebase-firestore library for android and is only included in the firebase-database (com.firebase.client.GenericTypeIndicator) android library.

To Reproduce:
Create a collection and a document with values ex:
{
"dude":"wow",
"whatever":32,
}
Retrieve item and convert to object with a with a generic map documentSnapshot.toObject(typeParameterClass)
Ex.: documentSnapshot.toObject(HashMap.class)

Relevant Code:

    java.lang.RuntimeException: Could not deserialize object. Class java.util.HashMap has generic type parameters, please use GenericTypeIndicator instead
        at com.google.firebase.firestore.util.CustomClassMapper.deserializeError(com.google.firebase:firebase-firestore@@17.1.5:524)
        at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-firestore@@17.1.5:232)
        at com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-firestore@@17.1.5:97)
        at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.5:203)
        at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.5:183)
        at // My package
        at // My package
        at com.google.firebase.firestore.DocumentReference.lambda$addSnapshotListenerInternal$2(com.google.firebase:firebase-firestore@@17.1.5:541)
        at com.google.firebase.firestore.DocumentReference$$Lambda$3.onEvent(Unknown Source:6)
        at com.google.firebase.firestore.util.ExecutorEventListener.lambda$onEvent$0(com.google.firebase:firebase-firestore@@17.1.5:42)
        at com.google.firebase.firestore.util.ExecutorEventListener$$Lambda$1.run(Unknown Source:6)
        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)
@wilhuff
Copy link
Contributor

wilhuff commented Feb 1, 2019

Thanks for pointing this out!

For the moment you can work around this in a few ways:

  1. In this specific case, documentSnapshot.getData() will return a Map<String, Object> containing the values you want ("wow" and 32). Of course you're likely interested in getting a Map of more interesting complex types and this doesn't handle that.

  2. If you know the keys ahead of time, you can create a simple wrapper struct

class DudeWhateverHolder {
  public String dude;
  public int whatever;
}

snapshot.toObject(DudeWhateverHolder.class);
  1. Alternatively, get(String, Class<T>) methods on the snapshot will also pull out complex values:
String dude = snapshot.get("dude", String.class);
int whatever = snapshot.get("whatever", Integer.class);
  1. If you have some specific homogeneous type you're trying to load then you can declare a subclass of the map you want like so:
class DudeWhateverMap extends HashMap<String, MyClass> {}

// Usage
snapshot.toObject(DudeWhateverMap.class);
  1. If you have lots of these you can also emulate the missing toObject(new GenericTypeIndicator<Map<String, MyClass>>() {}) with something like this:
public static <T> Map<String, T> toMapWithValues(Class<T> valueClass, DocumentSnapshot snapshot) {
  Map<String, T> result = new HashMap<>();
  for (String key : snapshot.getData().keys()) {
    T value = snapshot.get(key, valueClass);
    result.put(key, value);
  }
  return result;
}

// Usage
toMapWithValues(MyClass.class, snapshot);

Of course built-in support would be better, but the error message is erroneously pointing to a feature that doesn't exist rather than just a missing class. Fixing this isn't trivial and will require an additional public API review process so it won't happen too quickly.

Note that for heterogeneous values like those in your example (String and Integer), GenericTypeIndicator won't really help. The common supertype of values in your example would be Object and passing toObject(new GenericTypeIndicator<Map<String, Object>>() {}) would be essentially equivalent to calling getData().

@wilhuff
Copy link
Contributor

wilhuff commented Feb 1, 2019

Oh, and to be clear, I've added this to our backlog, but given the available workarounds we'll prioritize this along with other feature work.

@aguatno aguatno added the type: feature request New feature or request label Nov 19, 2019
@whalemare
Copy link

Still needed!

@joaoeudes7
Copy link

Nothing yet?

@schmidt-sebastian
Copy link
Contributor

We are still busy with a lot of other work, so unfortunately you have to apply the existing workarounds.

@angelcervera
Copy link

If no time to implement it, at least, workarounds should be in the documentation.

@schmidt-sebastian schmidt-sebastian self-assigned this Jan 31, 2022
@schmidt-sebastian schmidt-sebastian removed their assignment Apr 14, 2022
@Skaldebane
Copy link

No news here?

@cherylEnkidu
Copy link
Contributor

Hi @Skaldebane ,

The team is discussing this feature request (b/123794691). In the meantime we will update the error message.

daymxn pushed a commit that referenced this issue Jan 11, 2023
[Port of firebase/firebase-js-sdk#1120]

See firebase/firebase-ios-sdk#1499

This reworks our "user listener" into a "credential change listener" that
fires on any token change, even if the User did not change. This allows
us to restart our streams (but not switch mutation queues, etc.) on token
changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants