I'm trying to get some data from my Cloud Firestore into my Android App, but I'm having problem with enums. I have saved a String in the Cloud Firestore for the value of the enum, but when I convert the DocumentSnaphot I receive to an object, the app crashes because it's trying to convert the String to an enum based on the enum name (which isn't the same as the value).
The error I get is(I'm sending the value "NLD"):
java.lang.RuntimeException: Could not deserialize object. Could not find enum value of nl.gemoro.lgs.enums.CountryCode for value "NLD" (found in field 'address.countryCode')
The enum looks like this:
public enum CountryCode {
NETHERLANDS("NLD"),
UNKNOWN("???");
private final String value;
CountryCode(String s) {
value = s;
}
public boolean equalsValue(String otherValue) {
return value.equals(otherValue);
}
public String toString() {
return this.value;
}
}
I'm using this method to get the data from the Firestore and convert the DocumentSnapshot to the given class:
public static void getAllDocumentsConverted(String collection, final Class convertClass, final OperationCompletedListener listener) {
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection(collection)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Found " + task.getResult().size() + " documents");
List<Object> list = new ArrayList<>();
List<String> ids = new ArrayList<>();
for (DocumentSnapshot document : task.getResult()) {
list.add(document.toObject(convertClass));
ids.add(document.getId());
}
listener.onOperationComplete(Result.SUCCESS, list, ids);
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
listener.onOperationComplete(Result.FAILED);
}
}
});
}
I'm not sure if it's even people to get the result I want, but I would really like it if it did work some way.
EDIT: To be clear: I can convert the String to an enum if the enum just consists out of the enum names or if the names and values are the same.
Thanks in advance.
You can create Enum from String by using Enum. valueOf() method. valueOf() is a static method that is added on every Enum class during compile-time and it's implicitly available to all Enum along with values(), name(), and cardinal() methods.
Use the Enum. IsDefined() method to check if a given string name or integer value is defined in a specified enumeration. Thus, the conversion of String to Enum can be implemented using the Enum. Parse ( ) and Enum.
Cloud Firestore caches data that your app is actively using, so the app can write, read, listen to, and query data even if the device is offline.
If you are developing a Web or Node. js application that accesses Cloud Firestore on behalf of end users, use the firebase Client SDK. Note: This Cloud Firestore Server SDK does not support Firestore databases created in Datastore mode. To access these databases, use the Datastore SDK.
The enum cases need to match the possible String values exactly, including capitalization.
For example, if your country can have values of "NLD"
and "US"
, your enum should be structured like this:
public enum CountryCode {
NLD,
US
}
This lets Firebase automatically convert the String to an enum for the model you're converting to.
Note: Firebase uses <YourEnumType>.valueOf("value-from-doc")
to attempt to serialize to enums. You can't override valueOf
for enums in Java, so this is the best we can do at this time for serializing Strings to enums.
That being said, if you do it that way, you're opening yourself to an exception if you receive a value that doesn't match any of your enum values. Instead, you can use Android's @StringDef
annotation.
This allows you to set allowable values for you to check against and set in code, while allowing the actual value to be set to any String. This is useful if you get a bad value from your database. It's very similar to an enum. You can also use this to give yourself constant names that are different than possible String values you receive from Firebase.
You'd change your CountryCode
enum as follows:
public class ClassYouAreConvertingTo {
private static final String NETHERLANDS = "NLD";
private static final String UNKNOWN = "???";
@StringDef({NETHERLANDS, UNKNOWN})
@Retention(RetentionPolicy.SOURCE)
private @interface CountryCode {}
private String countryCode;
@CountryCode
public String getCountryCode() {
return this.countryCode;
}
}
Now country code can be set to any value, but Android Studio tries to make sure you only use NETHERLANDS and UNKNOWN constants when checking String equality. You'll get a red underline when using a different value (although the app will still compile and run).
IMO this is a safer, better solution than the enum route. Accept all values, but only care about the expected values in code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With