[Divulgation: je suis un ingénieur à Firebase. Cette question est censée être une question de référence pour répondre à plusieurs questions à la fois.]
J'ai la structure JSON suivante dans ma base de données Firebase:
{
"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
}
}
}
Je lis ceci avec le code suivant:
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) { }
});
Mais je reçois cette erreur:
Exception dans le fil "FirebaseEventTarget" com.firebase.client.FirebaseException: Échec de l'envoi du type
Comment puis-je lire mes utilisateurs dans des objets Java?
Firebase utilise Jackson pour permettre la sérialisation d'objets Java en JSON et la désérialisation de JSON en objets Java. Vous pouvez en savoir plus sur Jackson sur le site Web de Jackson et cette page sur les annotations de Jackson .
Dans la suite de cette réponse, nous allons montrer quelques façons courantes d’utiliser Jackson avec Firebase.
Le moyen le plus simple de charger les utilisateurs de Firebase dans Android est de créer une classe Java qui imite complètement les propriétés du JSON:
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+"\’}”; }
}
Nous pouvons utiliser cette classe dans un auditeur:
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) { }
});
Vous pouvez noter que la classe User suit le modèle de propriété JavaBean . Chaque propriété JSON est mappée par un champ de la classe User et nous avons une méthode de lecture publique pour chaque champ. En nous assurant que toutes les propriétés sont mappées avec le même nom, nous nous assurons que Jackson puisse les mapper automatiquement.
Vous pouvez également contrôler manuellement le mappage en mettant des annotations de Jackson sur votre classe Java, ses champs et ses méthodes. Nous allons couvrir les deux annotations les plus courantes (@JsonIgnore
et @JsonIgnoreProperties
) ci-dessous.
Dites que vous ne vous souciez que du nom de l'utilisateur et que vous le manipulez dans votre code Java. Supprimons la stackId
et voyons ce qui se passe:
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 + "\’}”;
}
}
Si nous attachons maintenant le même écouteur qu'auparavant et exécutons le programme, une exception sera générée:
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)
Le «type d’échec au traitement anti-rebond» indique que Jackson n’a pas pu désérialiser le JSON en objet User. Dans l'exception imbriquée, il nous explique pourquoi:
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 a trouvé une propriété stackId
dans le JSON et ne sait pas quoi en faire, alors il lève une exception. Heureusement, nous pouvons utiliser une annotation pour lui dire d'ignorer des propriétés spécifiques du JSON lors de son mappage vers notre classe User
:
@JsonIgnoreProperties({ “stackId" })
private static class User {
...
}
Si nous n'exécutons pas le code avec notre écouteur à nouveau, Jackson saura qu'il peut ignorer stackId
dans le JSON et qu'il sera capable de désérialiser le JSON dans un objet Utilisateur.
L'ajout de propriétés au JSON étant une pratique courante dans les applications Firebase, il peut être plus pratique de simplement dire à Jackson d'ignorer toutes les propriétés qui ne possèdent pas de mappage dans la classe Java:
@JsonIgnoreProperties(ignoreUnknown=true)
private static class User {
...
}
Maintenant, si nous ajoutons des propriétés au JSON ultérieurement, le code Java pourra toujours charger le User
s. N'oubliez pas que les objets Utilisateur ne contiennent pas toutes les informations présentes dans le JSON. Soyez donc prudent lorsque vous les écrivez à nouveau dans Firebase.
L'une des raisons pour lesquelles il est agréable d'avoir une classe Java personnalisée est que nous pouvons y ajouter des méthodes pratiques. Supposons que nous ajoutions une méthode pratique qui donne le nom à afficher pour un utilisateur:
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() + "'}";
}
}
Lisons maintenant les utilisateurs de Firebase et réécrivons-les dans un nouvel emplacement:
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) { }
});
Le JSON dans le noeud copiedusers
ressemble à ceci:
"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"
}
}
Ce n'est pas la même chose que le JSON source, car Jackson reconnaît la nouvelle méthode getDisplayName()
en tant que getter JavaBean et a donc ajouté une propriété displayName
au JSON qu'il génère. Nous résolvons ce problème en ajoutant une annotation JsonIgnore
à getDisplayName()
.
@JsonIgnore
public String getDisplayName() {
return getName() + "(" + getHandle() + ")";
}
Lors de la sérialisation d'un objet User, Jackson ignorera maintenant la méthode getDisplayName()
et le JSON que nous écrivons sera le même que celui que nous avons obtenu.
Les versions 9.x (et supérieures) du SDK Firebase pour Android/Java ont été arrêtées, y compris Jackson pour la sérialisation/désérialisation de Java <-> JSON. Le kit de développement logiciel plus récent fournit à la place un ensemble minimal d’annotations personnalisées permettant de contrôler les besoins de personnalisation les plus courants, tout en ayant un impact minimal sur la taille du fichier JAR/APK obtenu.
Ma réponse originale est toujours valable si vous êtes:
Le reste de cette réponse explique comment gérer les scénarios de sérialisation/désérialisation dans Firebase SDK 9.0 ou version ultérieure.
Nous allons commencer par cette structure JSON dans notre base de données Firebase:
{
"-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
}
}
À la base, nous pouvons charger chaque utilisateur de ce JSON dans la classe Java suivante:
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+ "'}"; }
}
Si nous déclarons les champs publics, nous n'avons même pas besoin des getters:
private static class CompleteUser {
public String handle;
public String name;
public long stackId;
}
Nous pouvons également charger partiellement un utilisateur, par exemple avec:
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 + "''}";
}
}
Lorsque nous utilisons cette classe pour charger les utilisateurs à partir du même JSON, le code est exécuté (contrairement à la variante de Jackson mentionnée dans mon autre réponse). Mais vous verrez un avertissement dans votre sortie de journalisation:
AVERTISSEMENT: aucun identifiant/champ pour stackId trouvé dans la classe Annotations $ PartialUser
Alors débarrassez-vous de cela, nous pouvons annoter la classe avec @IgnoreExtraProperties
:
@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 + "''}";
}
}
Comme auparavant, vous souhaiterez peut-être ajouter une propriété calculée à l'utilisateur. Vous voudriez ignorer une telle propriété lors de la sauvegarde des données dans la base de données. Pour ce faire, vous pouvez annoter la propriété/getter/setter/field avec @Exclude
:
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+ "'}"; }
}
Désormais, lors de l'écriture d'un utilisateur dans la base de données, la valeur de getTag()
sera ignorée.
Vous pouvez également spécifier le nom qu'un champ/getter/setter du code Java doit obtenir dans le code JSON de la base de données. Pour ce faire: annotez le champ/getter/setter avec @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+ "'}"; }
}
En général, il est préférable d’utiliser le mappage par défaut entre Java <-> JSON utilisé par le SDK Firebase. Cependant, @PropertyName
peut être nécessaire lorsque vous avez une structure JSON préexistante que vous ne pouvez pas mapper autrement à des classes Java.
Parce que votre mauvais dossier de chemin de requête dans root.this est example
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"