Serialización de Datos

Mientras un ImmutableDataManipulator es una buena manera de almacenar datos mientras el servidor está ejecutándose, no persistirá durante el reinicio. Sin embargo, cada implemento DataManipulator de la interfaz :javadoc:`DataSerializable`y así puede ser serializado a un :javadoc:`DataContainer` y deserailizado a un DataBuilder.

Después de esta conversación inicial del DataManipulator especializado para una estructura más general, el DataContainer se puede seguir procesando.

DataContainer y DataView

Un DataView es una estructura de propósito general para almacenar cualquier tipo de datos. Soporta múltiples valores e incluso anida DataViews como un valor, así permite una estructura de árbol. Cada valor es identificado por un DataQuery. Un DataContainer es una raíz DataView.

Cada DataSerializable proporciona un método toContainer() que creará y devolverá un DataContainer. Como un ejemplo, llamando toContainer() en una instancia HealthData producirá un DataContainer que contiene dos valores, uno para el estado actual y uno para la salud máxima, cada uno identificado por el DataQuery de la respectiva Llave.

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 este contenedor de vuelta a una instancia HealthData se realiza por el``DataBuilder`` correspondiente. Esos son registrados y administrados por el DataManager. También puede ser obtenido por una instancia válida de :javadoc:`Juego` o utilizando la clase de utilidad Sponge. El DataManager``proporciona un método para obtener el apropiado ``DataBuilder para deserializar una clase dada y adicionalmente un método abreviado para obtener el DataBuilder y hacer que realice la deserialización en un solo paso. Los siguientes dos ejemplos de código son funcionalmente equivalentes.

Ejemplo de Código: Deserialización, la manera larga

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

Ejemplo de Código: Deserialización, la manera corta

import org.spongepowered.api.data.manipulator.mutable.entity.HealthData;

public Optional<HealthData> deserializeHealth(DataView container) {
    return Sponge.getDataManager().deserialize(HealthData.class, container);
}

La función deserializeHealth devolverá Optional.empty()` si no hay ``DataBuilder` registrado para ``HealthData o el DataContainer suministrado está vacío. Si datos inválidos están presentes en el DataContainer, una InvalidDataException se producirá.

DataTranslator

En Sponge, generalmente las implementaciones MemoryDataView y MemoryDataContainer son utilizadas, las cuales residen solo en la memoria y así no persistirán después de reiniciar el servidor. Con el fin de almacenar persistentemente un DataContainer, primero tiene que ser convertido en una representación almacenable.

Utilizando la implementación DataTranslators#CONFIGURATION_NODE para DataTranslator, podemos convertir un DataView en un ConfigurationNode y viceversa. ConfigurationNodes puede entonces ser escrito y leído por un archivo persistente utilizando la Biblioteca de Configuración.

Ejemplo de Código: Serializar una instancia HealthData para Configuración

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

Ejemplo de Código: Deserializar una instancia HealthData desde Configuración

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