【问题标题】:Firebase Cloud Firestore – Convert String to Java EnumFirebase Cloud Firestore – 将字符串转换为 Java 枚举
【发布时间】:2018-08-24 09:57:29
【问题描述】:

我正在尝试将一些数据从我的 Cloud Firestore 获取到我的 Android 应用程序中,但我遇到了枚举问题。我已经在 Cloud Firestore 中为枚举值保存了一个字符串,但是当我将收到的 DocumentSnaphot 转换为一个对象时,应用程序崩溃了,因为它试图根据枚举名称将字符串转换为一个枚举(这不是t 与值相同)。

我得到的错误是(我正在发送值“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') 

枚举看起来像这样:

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;
    }
}

我正在使用此方法从 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);
                    }
                }
            });
}

我不确定是否有人能得到我想要的结果,但如果它确实以某种方式起作用,我真的很喜欢。

编辑: 明确一点:如果枚举仅由枚举名称组成,或者名称和值相同,我可以将字符串转换为枚举。

提前致谢。

【问题讨论】:

  • 如果你想使用一个类作为 Firebase 实体。类应该有公共的空构造函数(和值设置器/获取器)。枚举不是实体类。您可以创建一个包含枚举值的类。 stackoverflow.com/a/37376885/5272951

标签: java android firebase enums google-cloud-firestore


【解决方案1】:

枚举案例需要与可能的字符串值完全匹配,包括大小写。

例如,如果您所在的国家/地区可以有 "NLD""US" 的值,那么您的枚举应该是这样的结构:

public enum CountryCode {
    NLD,
    US
}

这让 Firebase 自动将字符串转换为您要转换为的模型的枚举。

注意:Firebase 使用 &lt;YourEnumType&gt;.valueOf("value-from-doc") 尝试序列化为枚举。您不能在 Java 中为枚举覆盖 valueOf,因此这是我们目前可以将字符串序列化为枚举的最佳方法。


话虽如此,如果你这样做,如果你收到一个与你的任何枚举值都不匹配的值,你就会向异常敞开心扉。相反,您可以使用Android's @StringDef annotation

这允许您设置允许的值以供您检查并在代码中设置,同时允许将实际值设置为任何字符串。如果您从数据库中获得错误值,这将很有用。它与枚举非常相似。您还可以使用它为自己指定与从 Firebase 收到的可能的 String 值不同的常量名称。

您可以按如下方式更改您的 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;
    }
}

现在可以将国家/地区代码设置为任何值,但 Android Studio 会尝试确保在检查字符串相等性时仅使用 NETHERLANDS 和 UNKNOWN 常量。使用不同的值时,您会看到一条红色下划线(尽管应用仍会编译和运行)。

IMO 这是比枚举路线更安全、更好的解决方案。接受所有值,但只关心代码中的预期值。

【讨论】:

    猜你喜欢
    • 2010-10-03
    • 1970-01-01
    • 2014-03-18
    • 2015-06-10
    • 1970-01-01
    • 2012-08-25
    • 2015-06-22
    • 1970-01-01
    相关资源
    最近更新 更多