Sérialiser des Données Customisées
Sans méthode de sérialisation et de désérialisation, vos données ne persisteront pas à travers les redémarrages. Sponge dispose de quelques moyens pour sérializer/désérialiser des données selon le type de données :
Les DataSerializables implémentent une interface pour effectuer la sérialisation, et utilisent le DataBuilder pour la désérialisation et la création
Les DataManipulators implémentent également
DataSerializable
, mais utilisent plutôt un DataManipulatorBuilder pour la désérialisation et la créationLes objets qui n’implémentent pas ou ne peuvent pas implémenter
DataSerializable
utilisent DataTranslator pour la sérialisation et la désérialisation
Cela signifie que partiquement n’importe quel objet en Java peut être sauvegardé sur le disque si il a été enregistré !
Lire les DataViews
Chaque fois que vous lisez un objet sérialisé, il est tentant de lire toutes les valeurs individuelles vous-même afin de créer manuellement tous les objets requis (et leurs paramètres) pour vos données. Toutefois, selon les données enregistrées dans le contenu, il y a quelques moyens qui sont bien plus pratiques :
Les types communs de Java tels que les
int
,String
,double
,List
etMap
peuvent être récupérés à l’aide des méthodes intégréesgetInt(DataQuery)
,getString(DataQuery)
, etc… Les listes de ces types peuvent aussi être récupérées de la même façon, par exemplegetStringList(DataQuery)
.Les objets
DataSerializable
peuvent être récupérés en utilisantgetSerializable(DataQuery, Class)
ougetSerializableList(DataQuery, Class)
. Avec le chemin, vous devez spécifier laClass
des types sérialisables, commeHome.class
.Les objets avec un
DataTranslator
enregistré peuvent être récupérés en utilisantgetObject(DataQuery, Class)
ougetObjectList(DataQuery, Class)
. Une liste complète des classes qui sont supportées par défaut peut être trouvée dans DataTranslators.
Dans tous les cas vous avez besoin de spécifier un chemin en utilisant un DataQuery. Si vos données ont une Key
correspondante c’est aussi simple que d’appeler key.getQuery()
. Sinon, la façon la plus simple de le faire est avec DataQuery.of("name")
.
Astuce
Les DataQueries peuvent être utilisés pour référencer les données de plusieurs nodes dans une arborescence en utilisant, par exemple, DataQuery.of("my", "custom", "data")
.
Les DataBuilders
Pour rendre un objet sérialisable, assurez-vous d’abord qu’il implémente DataSerializable. Vous devez seulement implémenter deux méthodes :
getContentVersion()
- Cela définit la version actuelle de vos données.toContainer()
- C’est ce qui sera donné à votre builder lorsque vous essayerez de désérialiser un objet. Vous pouvez stocker ce que vous voulez dans leDataContainer
retourné, du tant que c’est aussi sérialisable en utilisant une des méthodes ci-dessus. Utilisez simplement la méthodeset(DataQuery, Object)
pour sauvegarder vos données au chemin donné.
Astuce
Il est recommendé d’enregistrer la version de vos données vers le conteneur ainsi que d’utiliser Queries.CONTENT_VERSION
comme requête. Cela permettra de faire de la gestion de versions avec Les DataContentUpdaters.
Exemple de Code : Implémenter toContainer
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataQuery;
import org.spongepowered.api.data.Queries;
import org.spongepowered.api.data.MemoryDataContainer;
private String name = "Spongie";
@Override
public DataContainer toContainer() {
return DataContainer.createNew()
.set(DataQuery.of("Name"), this.name)
.set(Queries.CONTENT_VERSION, getContentVersion());
}
La prochaine partie consiste à implémenter un DataBuilder. Il est recommendé d’hériter AbstractDataBuilder puisqu’il va essayer de mettre à jour vos données si la version est inférieure à la version actuelle. Il y a une seule méthode que vous avez besoin d’implémenter - build(DataView)`, ou ``buildContent(DataView)
si vous utilisez AbstractDataBuilder
.
Vous voudrez vérifier que toutes les requêtes que vous voulez récupérer sont présentes en utilisant DataView.contains(Key...)
. Si non, les données sont probablemement incomplètes et vous devez retourner Optional.empty()
.
Si tout semble être présent, utilisez les méthodes ` getX`` pour construire des valeurs et retourner un nouvel objet créé en Optional
.
Les DataContentUpdaters
Que se passe-t-il si vous changer la disposition des données dans une nouvelle version ? Les DataContentUpdaters résolvent ce problème. Si l’objet sérialisé est inférieure à la version actuelle, un AbstractDataBuilder
va essayer de mettre à jour les données avant de le passer au builder.
Chaque updater a une version d’entrée et une version de sortie. Vous devez prendre les anciennes données et changer tout ce qui est nécessaire pour mettre à jour vers une nouvelle disposition. Si c’est impossible de convertir en raison de données manquantes, il est possible de fournir à la place une valeur par défaut qui est interprétée ailleurs - comme par le builder principal ou l’objet lui-même.
Finalement, vous devez vous assurez que tous les DataContentUpdater
s sont enregistrés avec DataManager#registerContentUpdater()
en référançant la classe de données principale - cela leur permettra d’être découverts par le builder.
Exemple de Code : Implémenter un DataContentUpdater
import org.spongepowered.api.data.persistence.DataContentUpdater
import org.spongepowered.api.text.Text
public class NameUpdater implements DataContentUpdater {
@Override
public int getInputVersion() {
return 1;
}
@Override
public int getOutputVersion() {
return 2;
}
@Override
public DataView update(DataView content) {
String name = content.getString(DataQuery.of("Name")).get();
// For example, version 2 uses a text for the name
return content.set(DataQuery.of("Name"), Text.of(name));
}
}
Les DataManipulatorBuilders
Un DataManipulatorBuilder
est très similaire au DataBuilder
, mais il ajoute quelques méthodes directement associées à la désérialisation des manipulators :
create()
doit retourner un nouveau manipulator avec les valeurs par défautcreateFrom(DataHolder)
est similaire à la méthode build, mais à la place, les valeurs doivent être prises sur le DataHolder. Si il n’y a aucune donnée à récupérer depuis le holder, retournez juste la sortie decreate()
. Si les données sont incompatibles avec leDataHolder
, vous devez retourner unOptional.empty()
à la place.
Comme le DataBuilder
, vous devez lire et retourner votre manipulator dans la méthode build
appropriée.
Les DataManipulatorBuilder
s peuvent faire usage des Les DataContentUpdaters aussi, du temps que vous implémentez AbstractDataBuilder
.
Enregistrer un DataManipulatorBuilder
est également semblable au DataBuilder
mais utilise la méthode register()
. Vous devez référencer vos deux classes mutables et immuables dans la méthode, en plus d’une instance de votre builder.
Note
Vous devez référencer les classes d’implémentation si vous avez divisé l’API de l’implémentation.
Les DataTranslators
Souvent les objets que vous voulez sérialiser ne sont pas des objets qui implémentent DataSerializable
, comme Vector3d
ou Date
. Pour autoriser ces objets vous devez implémenter un DataTranslator qui gère à la fois la sérialisation et la désérialisation de l’objet.
L’implémentation de translate
est identique à toContainer()
et build(DataView)
pour un DataSerializable
comme montré ci-dessus, excepté qu’une InvalidDataException
est levée si les données sont manquantes à la place de retourner un Optional
.
Comme pour les autres données, assurez-vous d’enregistrer le translator pendant l’événement GameRegistryEvent.Register<DataTranslator<?>>
.