wake-up-neo.com

Warum erhalte ich die Fehlermeldung, dass das Schreiben nicht funktioniert?

[Offenlegung: Ich bin Ingenieur bei Firebase. Diese Frage soll als Referenzfrage dienen, um viele Fragen auf einmal zu beantworten.]

Ich habe die folgende JSON-Struktur in meiner Firebase-Datenbank:

{  
  "users": {
    "-Jx5vuRqItEF-7kAgVWy": {
        "handle": "puf",
        "name": "Frank van Puffelen",
        "soId": 209103
    },
    "-Jx5w3IOHD2kRFFgkMbh": {
        "handle": "kato",
        "name": "Kato Wulf",
        "soId": 394010
    },
    "-Jx5x1VWs08Zc5S-0U4p": {
        "handle": "mimming",
        "name": "Jenny Tong",
        "soId": 839465
    }
  }
}

Ich lese dies mit dem folgenden Code:

private static class User {
    String handle;
    String name;

    public String getHandle() { return handle; }
    public String getName() { return name; }
}

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

Aber ich bekomme diesen Fehler:

Ausnahme im Thread "FirebaseEventTarget" com.firebase.client.FirebaseException: Fehler beim Bounce-Typ

Wie kann ich meine Benutzer in Java-Objekte einlesen?

37

Firebase verwendet Jackson, um die Serialisierung von Java-Objekten in JSON und die Deserialisierung von JSON in Java-Objekte zu ermöglichen. Mehr über Jackson finden Sie auf der Jackson-Website und diese Seite über Jackson-Anmerkungen

Im Rest dieser Antwort zeigen wir einige gängige Möglichkeiten, Jackson mit Firebase zu verwenden.

Komplette Benutzer werden geladen

Die einfachste Möglichkeit, die Benutzer von Firebase in Android zu laden, besteht darin, eine Java-Klasse zu erstellen, die die Eigenschaften im JSON vollständig nachahmt:

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+"\’}”; }
}

Wir können diese Klasse in einem Listener verwenden:

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

Sie können beachten, dass die User-Klasse dem JavaBean-Eigenschaftsmuster folgt. Jede JSON-Eigenschaft wird durch ein Feld in der User-Klasse zugeordnet, und für jedes Feld gibt es eine öffentliche Getter-Methode. Indem wir sicherstellen, dass alle Eigenschaften mit demselben Namen abgebildet werden, stellen wir sicher, dass Jackson sie automatisch zuordnen kann.

Sie können das Mapping auch manuell steuern, indem Sie Jackson-Anmerkungen in Ihre Java-Klasse sowie deren Felder und Methoden einfügen. Nachfolgend werden die zwei häufigsten Anmerkungen (@JsonIgnore und @JsonIgnoreProperties) behandelt.

Benutzer werden teilweise geladen

Nehmen Sie an, Sie kümmern sich nur um den Namen des Benutzers und den Umgang mit Ihrem Java-Code. Lassen Sie uns die stackId entfernen und sehen, was passiert:

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 + "\’}”; 
  }
}

Wenn wir jetzt denselben Listener wie zuvor anhängen und das Programm ausführen, wird eine Ausnahme ausgelöst:

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)

Der Typ "Fehler beim Entprellen" zeigt an, dass Jackson die JSON nicht in ein Benutzerobjekt deserialisieren konnte. In der verschachtelten Ausnahme wird erklärt, warum:

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: [email protected]; line: 1, column: 15] (through reference chain: com.firebase.User["stackId"])

at com.shaded.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.Java:79)

Jackson hat eine Eigenschaft stackId in der JSON gefunden und weiß nicht, was er damit tun soll. Es löst also eine Ausnahme aus. Glücklicherweise gibt es eine Anmerkung, mit der wir ihm mitteilen können, dass bestimmte Eigenschaften aus dem JSON ignoriert werden sollen, wenn sie auf unsere User-Klasse abgebildet werden:

@JsonIgnoreProperties({ “stackId" })
private static class User {
  ...
}

Wenn wir den Code nicht erneut mit unserem Listener ausführen, weiß Jackson, dass er stackId in der JSON ignorieren kann und die JSON erneut in ein Benutzerobjekt deserialisieren kann.

Da das Hinzufügen von Eigenschaften zu JSON in Firebase-Anwendungen eine übliche Praxis ist, empfiehlt es sich möglicherweise, Jackson zu sagen, dass er alle Eigenschaften ignorieren soll, für die in der Java-Klasse keine Zuordnung vorhanden ist:

@JsonIgnoreProperties(ignoreUnknown=true)
private static class User {
  ...
}

Wenn wir dem JSON später Eigenschaften hinzufügen, kann der Java-Code weiterhin die Variable Users laden. Denken Sie jedoch daran, dass die Benutzerobjekte nicht alle Informationen enthalten, die in der JSON vorhanden waren. Seien Sie also vorsichtig, wenn Sie sie erneut in Firebase zurückschreiben.

Benutzer teilweise einsparen

Ein Grund, warum es nett ist, eine angepasste Java-Klasse zu haben, ist, dass wir bequeme Methoden hinzufügen können. Angenommen, wir fügen eine Komfortmethode hinzu, die den Namen für einen Benutzer anzeigt:

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() + "'}"; 
  }
}

Nun lesen wir die Benutzer von Firebase und schreiben sie an einen neuen Ort zurück:

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

Die JSON im Knoten copiedusers sieht folgendermaßen aus:

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

Dies ist nicht dasselbe wie beim Quell-JSON, da Jackson die neue getDisplayName()-Methode als JavaBean-Getter erkennt und somit dem ausgegebenen JSON eine displayName-Eigenschaft hinzufügt. Wir lösen dieses Problem, indem Sie eine JsonIgnore-Anmerkung zu getDisplayName() hinzufügen.

    @JsonIgnore
    public String getDisplayName() {
        return getName() + "(" + getHandle() + ")";
    }

Bei der Serialisierung eines Benutzerobjekts ignoriert Jackson nun die getDisplayName()-Methode, und der JSON, den wir ausschreiben, ist identisch mit dem, was wir bekommen haben.

49

Die 9.x-Version (und höher) des Firebase SDK für Android/Java wurde eingestellt, einschließlich Jackson für die Serialisierung/Deserialisierung von Java <-> JSON. Das neuere SDK bietet stattdessen einen minimalen Satz an benutzerdefinierten Anmerkungen, um die häufigsten Anpassungserfordernisse zu steuern und die resultierende JAR/APK-Größe minimal zu beeinflussen.


Meine ursprüngliche Antwort ist noch gültig, wenn Sie:

Der Rest dieser Antwort behandelt den Umgang mit Serialisierungs-/Deserialisierungsszenarien in Firebase SDK 9.0 oder höher.


Datenstruktur

Wir beginnen mit dieser JSON-Struktur in unserer Firebase-Datenbank:

{
  "-Jx86I5e8JBMZ9tH6W3Q" : {
    "handle" : "puf",
    "name" : "Frank van Puffelen",
    "stackId" : 209103,
    "stackOverflowId" : 209103
  },
  "-Jx86Ke_fk44EMl8hRnP" : {
    "handle" : "mimming",
    "name" : "Jenny Tong",
    "stackId" : 839465
  },
  "-Jx86N4qeUNzThqlSMer" : {
    "handle" : "kato",
    "name" : "Kato Wulf",
    "stackId" : 394010
  }
}

Komplette Benutzer werden geladen

Grundsätzlich können wir jeden Benutzer aus dieser JSON-Klasse in die folgende Java-Klasse laden:

private static class CompleteUser {
    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+ "'}"; }
}

Wenn wir die Felder als öffentlich deklarieren, brauchen wir nicht einmal die Getter:

private static class CompleteUser {
    public String handle;
    public String name;
    public long stackId;
}

Benutzer werden teilweise geladen

Wir können einen Benutzer auch teilweise laden, zum Beispiel mit:

private static class PartialUser {
    String handle;
    String name;

    public String getHandle() {
        return handle;
    }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "User{handle='" + handle + "', NAME='" + name + "''}";
    }
}

Wenn wir diese Klasse verwenden, um die Benutzer von derselben JSON zu laden, wird der Code ausgeführt (im Gegensatz zur Jackson-Variante, die in meiner anderen Antwort erwähnt wurde). In Ihrer Protokollierungsausgabe wird jedoch eine Warnung angezeigt:

WARNUNG: In der Klasse Anmerkungen $ PartialUser wurde kein Setter/Feld für stackId gefunden

Also los damit, wir können die Klasse mit @IgnoreExtraProperties annotieren:

@IgnoreExtraProperties
private static class PartialUser {
    String handle;
    String name;

    public String getHandle() {
        return handle;
    }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "User{handle='" + handle + "', NAME='" + name + "''}";
    }
}

Benutzer teilweise einsparen

Wie zuvor möchten Sie dem Benutzer möglicherweise eine berechnete Eigenschaft hinzufügen. Sie möchten eine solche Eigenschaft ignorieren, wenn Sie die Daten in der Datenbank speichern. Zu diesem Zweck können Sie das Feld property/getter/setter/mit @Exclude kommentieren:

private static class OvercompleteUser {
    String handle;
    String name;
    long stackId;

    public String getHandle() { return handle; }
    public String getName() { return name; }
    public long getStackId() { return stackId; }

    @Exclude
    public String getTag() { return getName() + " ("+getHandle()+")"; }

    @Override
    public String toString() { return "User{handle='"+handle+"', name='"+name+"', stackId="+stackId+ "'}"; }
}

Wenn Sie nun einen Benutzer in die Datenbank schreiben, wird der Wert von getTag() ignoriert.

Verwenden Sie im JSON einen anderen Eigenschaftennamen als im Java-Code

Sie können auch angeben, welchen Namen ein Feld/Getter/Setter aus dem Java-Code in der JSON in der Datenbank erhalten soll. Gehen Sie dazu folgendermaßen vor: Kommentieren Sie das Feld/Getter/Setter mit @PropertyName().

private static class UserWithRenamedProperty {
    String handle;
    String name;
    @PropertyName("stackId")
    long stackOverflowId;

    public String getHandle() { return handle; }
    public String getName() { return name; }
    @PropertyName("stackId")
    public long getStackOverflowId() { return stackOverflowId; }

    @Override
    public String toString() { return "User{handle='"+handle+"', name='"+name+"', stackId="+stackOverflowId+ "'}"; }
}

Im Allgemeinen ist es am besten, die Standardzuordnung zwischen Java <-> JSON zu verwenden, die das Firebase-SDK verwendet. @PropertyName kann jedoch erforderlich sein, wenn Sie bereits über eine JSON-Struktur verfügen, die Sie sonst nicht Java-Klassen zuordnen können.

3

Weil Ihr falscher Abfragepfadordner in root.this beispiel ist. enter image description here

My code:
    private void GetUpdates(DataSnapshot snapshot){
        romchat.clear();
        for (DataSnapshot ds: snapshot.getChildren()){
            Rowitemroom row = new Rowitemroom();
            row.setCaption(ds.getValue(Rowitemroom.class).getCaption());
            row.setFileUrl(ds.getValue(Rowitemroom.class).getFileUrl());
            romchat.add(row);
/*            Rowitemroom row = snapshot.getValue(Rowitemroom.class);
            String caption = row.getCaption();
            String url = row.getFileUrl();*/

        }
        if (romchat.size()>0){
            adapter = new CustomRoom(context,romchat);
            recyclerView.setAdapter(adapter);
        }else {
            Toast.makeText(context, "No data", Toast.LENGTH_SHORT).show();
        }
    }
        db_url ="your apps`enter code here`.appspot.com/admins"
0
Chung Nguyen