Firebase 使用 Jackson 允许将 Java 对象序列化为 JSON,并将 JSON 反序列化回 Java 对象。您可以在杰克逊网站上找到有关杰克逊的更多信息,也可以在有关杰克逊注释的此页面上找到。
在这个答案的其余部分,我们将展示一些将Jackson与Firebase一起使用的常见方法。
加载完整用户
将用户从Firebase加载到Android的最简单方法是创建一个完全模仿JSON中属性的Java类:
private static class User {
String handle;
String name;
long stackId;
public String getHandle() { return handle; }
public String getName() { return name; }
public long getStackId() { return stackId; }
@Override
public String toString() { return "User{handle='"+handle+“', name='"+name+"', stackId="+stackId+"\’}”; }
}
我们可以在侦听器中使用此类:
Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/32108969/users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot usersSnapshot) {
for (DataSnapshot userSnapshot : usersSnapshot.getChildren()) {
User user = userSnapshot.getValue(User.class);
System.out.println(user.toString());
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
您可能会注意到,User 类遵循 JavaBean 属性模式。每个 JSON 属性都由 User 类中的一个字段映射,我们为每个字段都有一个公共 getter 方法。通过确保所有属性都以完全相同的名称进行映射,我们确保 Jackson 可以自动映射它们。
您还可以通过将 Jackson 注释放在 Java 类及其字段和方法上来手动控制映射。我们将在下面介绍两个最常见的注释( 和 )。@JsonIgnore
@JsonIgnoreProperties
部分加载用户
假设您在 Java 代码中只关心用户名和句柄。让我们删除 并查看会发生什么:stackId
private static class User {
String handle;
String name;
public String getHandle() { return handle; }
public String getName() { return name; }
@Override
public String toString() {
return "User{handle='" + handle + “\', name='" + name + "\’}”;
}
}
如果我们现在附加与以前相同的侦听器并运行程序,它将引发异常:
Exception in thread "FirebaseEventTarget" com.firebase.client.FirebaseException: Failed to bounce to type
at com.firebase.client.DataSnapshot.getValue(DataSnapshot.java:187)
at com.firebase.LoadPartialUsers$1.onDataChange(LoadPartialUsers.java:16)
“未能反去抖类型”表示 Jackson 无法将 JSON 反序列化为 User 对象。在嵌套异常中,它告诉我们为什么:
Caused by: com.shaded.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "stackId" (class com.firebase.LoadPartialUsers$User), not marked as ignorable (2 known properties: , "handle", "name"])
at [Source: java.io.StringReader@43079089; line: 1, column: 15] (through reference chain: com.firebase.User["stackId"])
at com.shaded.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
Jackson 在 JSON 中发现了一个属性,但不知道该如何处理它,因此它引发了一个异常。幸运的是,有一个注释,我们可以用它来告诉它在将JSON映射到我们的类时忽略JSON中的特定属性:stackId
User
@JsonIgnoreProperties({ "stackId" })
private static class User {
...
}
如果我们不再使用侦听器运行代码,Jackson 将知道它可以在 JSON 中忽略,并且能够再次将 JSON 反序列化为 User 对象。stackId
由于在 Firebase 应用程序中向 JSON 添加属性是一种常见的做法,因此您可能会发现,简单地告诉 Jackson 忽略 Java 类中没有映射的所有属性会更方便:
@JsonIgnoreProperties(ignoreUnknown=true)
private static class User {
...
}
现在,如果我们稍后将属性添加到 JSON,Java 代码仍将能够加载 s。请记住,用户对象不会包含 JSON 中存在的所有信息,因此在再次将其写回 Firebase 时要小心。User
部分节省用户
拥有自定义Java类很好的一个原因是我们可以为其添加方便的方法。假设我们添加了一个方便的方法,用于获取要为用户显示的名称:
private static class User {
String handle;
String name;
public String getHandle() { return handle; }
public String getName() { return name; }
@JsonIgnore
public String getDisplayName() {
return getName() + " (" + getHandle() + ")";
}
@Override
public String toString() {
return "User{handle='" + handle + "\', name='" + name + "\', displayName='" + getDisplayName() + "'}";
}
}
现在,让我们从 Firebase 读取用户,并将其写回新位置:
Firebase srcRef = new Firebase("https://stackoverflow.firebaseio.com/32108969/users");
final Firebase copyRef = new Firebase("https://stackoverflow.firebaseio.com/32108969/copiedusers");
srcRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot usersSnapshot) {
for (DataSnapshot userSnapshot : usersSnapshot.getChildren()) {
User user = userSnapshot.getValue(User.class);
copyRef.child(userSnapshot.getKey()).setValue(user);
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
节点中的 JSON 如下所示:copiedusers
"copiedusers": {
"-Jx5vuRqItEF-7kAgVWy": {
"displayName": "Frank van Puffelen (puf)",
"handle": "puf",
"name": "Frank van Puffelen"
},
"-Jx5w3IOHD2kRFFgkMbh": {
"displayName": "Kato Wulf (kato)",
"handle": "kato",
"name": "Kato Wulf"
},
"-Jx5x1VWs08Zc5S-0U4p": {
"displayName": "Jenny Tong (mimming)",
"handle": "mimming",
"name": "Jenny Tong"
}
}
这与源 JSON 不同,因为 Jackson 将新方法识别为 JavaBean getter,因此向它输出的 JSON 添加了一个属性。我们通过向 中添加注释来解决此问题。getDisplayName()
displayName
JsonIgnore
getDisplayName()
@JsonIgnore
public String getDisplayName() {
return getName() + "(" + getHandle() + ")";
}
序列化 User 对象时,Jackson 现在将忽略该方法,我们写出的 JSON 将与我们获取的 JSON 相同。getDisplayName()