有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

安卓 Firebase Cloud Firestore–将字符串转换为Java枚举

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

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

我不确定人们是否能得到我想要的结果,但我真的希望它能以某种方式起作用

编辑: 需要明确的是:如果枚举只是由枚举名称组成,或者如果名称和值相同,我可以将字符串转换为枚举

提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    枚举案例需要精确匹配可能的字符串值,包括大小写

    例如,如果您的国家/地区可以有"NLD""US"的值,则您的枚举的结构应如下所示:

    public enum CountryCode {
        NLD,
        US
    }
    

    这使Firebase能够自动将字符串转换为要转换到的模型的枚举

    注意:Firebase使用<YourEnumType>.valueOf("value-from-doc")尝试序列化到枚举。在Java中,您不能为枚举重写valueOf,因此这是目前我们为将字符串序列化到枚举所能做的最好的事情


    也就是说,如果您这样做,那么如果您收到的值与任何枚举值都不匹配,您将面临一个异常。相反,您可以使用Android's ^{} annotation

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

    您将更改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尝试确保在检查字符串相等性时只使用荷兰和未知常量。当使用不同的值时,您将得到一条红色下划线(尽管应用程序仍将编译并运行)

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