简体   繁体   English

Firebase Cloud Firestore - 将字符串转换为Java Enum

[英]Firebase Cloud Firestore – Convert String to Java Enum

I'm trying to get some data from my Cloud Firestore into my Android App, but I'm having problem with enums. 我正在尝试从我的Cloud Firestore获取一些数据到我的Android应用程序中,但我遇到了枚举问题。 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). 我已经在Cloud Firestore中保存了一个字符串的值,但是当我将DocumentSnaphot转换为一个对象时,应用程序崩溃了,因为它试图根据枚举名称将字符串转换为枚举(这不是'与价值相同)。

The error I get is(I'm sending the value "NLD"): 我得到的错误是(我发送的值是“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: 我正在使用此方法从Firestore获取数据并将DocumentSnapshot转换为给定的类:

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. 提前致谢。

The enum cases need to match the possible String values exactly, including capitalization. 枚举案例需要准确匹配可能的String值,包括大小写。

For example, if your country can have values of "NLD" and "US" , your enum should be structured like this: 例如,如果您所在的国家/地区的值可以是"NLD""US" ,则您的枚举结构应如下所示:

public enum CountryCode {
    NLD,
    US
}

This lets Firebase automatically convert the String to an enum for the model you're converting to. 这使Firebase可以自动将String转换为您要转换为的模型的枚举。

Note: Firebase uses <YourEnumType>.valueOf("value-from-doc") to attempt to serialize to enums. 注意:Firebase使用<YourEnumType>.valueOf("value-from-doc")尝试序列化为枚举。 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. 您不能覆盖Java中枚举的valueOf ,因此这是我们目前用于将字符串序列化为枚举的最佳方法。


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 . 相反,您可以使用Android的@StringDef注释

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. 这允许您设置允许值以检查和设置代码,同时允许将实际值设置为任何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. 您也可以使用它为自己提供与从Firebase收到的可能字符串值不同的常量名称。

You'd change your CountryCode enum as follows: 您将更改CountryCode枚举,如下所示:

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. 现在国家/地区代码可以设置为任何值,但Android Studio会在检查字符串相等性时尝试确保仅使用NETHERLANDS和UNKNOWN常量。 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. IMO这是一个比枚举路径更安全,更好的解决方案。 Accept all values, but only care about the expected values in code. 接受所有值,但只关心代码中的预期值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM