2 votes

Utilisation de différentes classes pour mapper des données JSON avec GSON

Mon application reçoit des messages JSON depuis une connexion WebSocket.

Il existe différents types de réponses, qui sont formatées de cette manière :

{
    "type": "snapshot",
    "product_id": "BTC-EUR",
    "bids": [["1", "2"]],
    "asks": [["2", "3"]]
}

ou

{
    "type": "l2update",
    "product_id": "BTC-EUR",
    "changes": [
        ["buy", "1", "3"],
        ["sell", "3", "1"],
        ["sell", "2", "2"],
        ["sell", "4", "0"]
    ]
}

... par exemple (voir API complète aquí ).

En fonction du "type", je voudrais que GSON mappe une classe différente (par exemple, Snapshot.class et l2update.class).

J'ai des gestionnaires de messages qui s'abonnent à la connexion WebSocket et je veux que le message soit traité par le gestionnaire approprié. Par exemple :

  • ErrorMessageHandler gère les erreurs.
  • SnapshotMessageHandler créerait le carnet d'ordres initial.
  • L2UpdateMessageHandler mettrait à jour le carnet d'ordres.
  • et ainsi de suite

Mon problème est de distribuer les messages en fonction de leur type.

Je pensais les convertir dans la classe appropriée, puis appeler le gestionnaire correspondant en utilisant une fabrique. Je suis actuellement bloqué à la première étape, la conversion du JSON dans Error.class ou Snapshot.class selon le "type".

Comment puis-je faire ça ?

1voto

stdunbar Points 5256

Vous pouvez envisager d'utiliser une bibliothèque qui nécessite un peu moins un modèle d'objet solide, du moins au début. J'utilise JsonPath pour ce genre de choses. Tu pourrais l'utiliser pour au moins trouver le type que vous avez en face de vous :

String type = JsonPath.read(yourIncomingJson, "$.type");

et ensuite, sur la base de la chaîne, faites une déclaration de commutation comme le suggère @ShafinMahmud.

Toutefois, vous pouvez également utiliser JsonPath pour l'ensemble du processus. Vous pourriez lire toutes les valeurs en utilisant la notation du chemin et savoir comment les analyser en fonction du type.

L'ajout d'une autre bibliothèque pour lire une seule valeur peut ou non vous convenir, mais si vous l'utilisez pour lire d'autres valeurs, cela peut s'avérer utile.

1voto

pirho Points 5491

Pour Gson, vous pouvez utiliser com.google.gson.typeadapters.RuntimeTypeAdapterFactory .

Supposons que vous ayez - par exemple - les classes suivantes :

public class BaseResponse {
    private String type, product_id;
    // rest of the common fields
}

public class Snapshot extends BaseResponse {    
    // rest of the fields
}

public class L2Update extends BaseResponse {    
    // rest of the fields
}

alors vous devez construire ce qui suit RuntimeTypeAdapterFactory :

RuntimeTypeAdapterFactory<BaseResponse> runtimeTypeAdapterFactory = 
    RuntimeTypeAdapterFactory
        .of(BaseResponse.class, "type") // set the field where to look for value
        .registerSubtype(L2Update.class, "l2update") // values map to 'type' 
        .registerSubtype(Snapshot.class, "snapshot");// value in json

L'enregistrement avec Gson permettra ensuite l'instanciation automatique de chaque type de réponse :

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();

et fournir BaseResponse para fromJson(..) si vous l'utilisez, comme :

gson.fromJson( json , BaseResponse.class);

NOTE : que Gson omet de dé- & sérialiser les type champ. Cependant, il doit être défini dans Json. Comme c'est le cas maintenant dans les réponses que vous recevez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X