Sérialisation de données
Alors qu’un ImmutableDataManipulator est une bonne façon de stocker des données pendant que le serveur est allumé, il ne va pas persister après un redémarrage. Toutefois, chaque DataManipulator implémente l’interface DataSerializable et peut donc être sérialisé en un DataContainer et désérialiser par un DataBuilder.
Après cette conversion initiale depuis le DataManipulator
spécialisé vers une structure plus générale, le DataContainer
peut être traité ultérieurement.
DataContainer et DataView
Un DataView est une structure polyvalente pour tenir tout type de données. Il supporte plusieurs valeurs et même imbriquer DataView
s comme valeur, ce qui permet une structure arborescente. Chaque valeur est identifée par un DataQuery. Un DataContainer
est un DataView
racine.
Chaque DataSerializable
fournit une méthode toContainer()
qui va créé et retourner un DataContainer
. Par exemple, appeler toContainer()
sur une instance de HealthData va produire un DataContainer
contenant deux valeurs, une pour la santé actuelle et une pour la santé maximale, chacune étant identifée par le DataQuery
de la Key
respective.
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.key.Keys;
DataContainer serializedHealth = healthData.toContainer();
double currentHealth = serializedHealth.getDouble(Keys.HEALTH.getQuery()).get();
currentHealth == healthData.health().get(); // true
Convertir ce conteneur en une instance d”HealthData
se fait par le DataBuilder
correspondant. Ils sont enregistrés et gérés par le DataManager. Ils peuvent être soit obtenus depuis une instance valide de Game ou en utilisant la classe utilitaire Sponge. Le DataManager
fournit une méthode pour récupérer le DataBuilder
approprié pour désérialiser une classe donnée et, en outre, une méthode plus courte pour récupérer le DataBuilder
et lui faire faire la désérialisation en une étape. Les deux exemples de code suivants sont fonctionnellement équivalents.
Exemple de Code : Désérialisation, la façon longue
import org.spongepowered.api.data.DataView;
import org.spongepowered.api.data.manipulator.mutable.entity.HealthData;
import org.spongepowered.api.util.persistence.DataBuilder;
import java.util.Optional;
public Optional<HealthData> deserializeHealth(DataView container) {
final Optional<DataBuilder<HealthData>> builder = Sponge.getDataManager().getBuilder(HealthData.class);
if (builder.isPresent()) {
return builder.get().build(container);
}
return Optional.empty();
}
Exemple de Code : Désérialisation, la façon courte
import org.spongepowered.api.data.manipulator.mutable.entity.HealthData;
public Optional<HealthData> deserializeHealth(DataView container) {
return Sponge.getDataManager().deserialize(HealthData.class, container);
}
La fonction ` deserializeHealth`` va retourner Optional.empty()
sil il n’y a pas de DataBuilder
enregistré pour HealthData
ou si le DataContainer
fournit est vide. Si des données invalides sont présentes dans le DataContainer
, une InvalidDataException sera levée.
DataTranslator
Dans Sponge, généralement les implémentations MemoryDataView et MemoryDataContainer sont utilisés, qui résident en mémoire uniquement et ne persistent donc pas après un redémarrage. Afin de constamment stocker un DataContainer
, il doit d’abord être converti en une représentation stockable.
En utilisant l’implémentation DataTranslators#CONFIGURATION_NODE de DataTranslator, nous pouvons convertir un DataView
en ConfigurationNode et vice versa. Les ConfigurationNode
s peuvent ensuite être écrites et lues depuis des fichiers persistants à l’aide de la Librairie Configurate.
Exemple de Code : Sérialiser une instance d’HealthData pour Configurate
import ninja.leaping.configurate.ConfigurationNode;
import org.spongepowered.api.data.persistence.DataTranslator;
import org.spongepowered.api.data.persistence.DataTranslators;
public ConfigurationNode translateToConfig(HealthData data) {
final DataTranslator<ConfigurationNode> translator = DataTranslators.CONFIGURATION_NODE;
final DataView container = data.toContainer();
return translator.translate(container);
}
Exemple de Code : Désérialiser une instance d’HealthData depuis Configurate
import java.util.Optional;
public Optional<HealthData> translateFromConfig(ConfigurationNode node) {
final DataTranslator<ConfigurationNode> translator = DataTranslators.CONFIGURATION_NODE;
final DataView container = translator.translate(node);
return deserializeHealth(container);
}