JSON es un formato de texto para intercambiar datos. Es un subconjunto de la notación de objetos de JavaScript y se considera un formato independiente del lenguaje. Se utiliza para serializar datos estructurados e intercambiarlos a través de una red. Es fácil de leer y escribir y permite que el software lo analice y genere con facilidad.

La librería guardará un archivo JSON para cada modelo. La búsqueda se hace mediante el ID del modelo para acceder a él directamente sin cargar datos innecesarios.

Serialización y deserialización

import com.google.gson.JsonObject;
import es.revengenetwork.storage.codec.ModelDeserializer;
import es.revengenetwork.storage.codec.ModelSerializer;
import es.revengenetwork.storage.gson.codec.JsonReader;
import es.revengenetwork.storage.gson.codec.JsonWriter;
import org.jetbrains.annotations.NotNull;

public final class UserModelCodec {
  private UserModelCodec() {
    throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
  }

	public enum Serializer implements ModelSerializer<UserModel, JsonObject> {
    INSTANCE; // Usamos lazy singleton para poder acceder a la instancia desde cualquier lugar

    @Override
    public @NotNull JsonObject serialize(final @NotNull UserModel userModel) {
      return JsonWriter.create()
               .writeString("id", userModel.id())
               .writeString("name", userModel.name())
               .writeNumber("age", userModel.age())
               .writeDate("birthday", userModel.birthday())
               .end();
    }
  }

  public enum Deserializer implements ModelDeserializer<UserModel, JsonObject> {
    INSTANCE; // Usamos lazy singleton para poder acceder a la instancia desde cualquier lugar

		// Lo suprimimos ya que jamás nuestros datos deberían ser
		// nulos para este caso ya que nos aseguramos de escribirlos todos de forma correcta
    @SuppressWarnings("DataFlowIssue")
    @Override
    public @NotNull UserModel deserialize(final @NotNull JsonObject serialized) {
      final var reader = JsonReader.create(serialized);
      return new UserModel(
        reader.readString("id"),
        reader.readString("name"),
        reader.readInt("age"),
        reader.readDate("birthday"));
    }
  }
}

Creando los repositories

Sin caché

final AsyncModelRepository<UserModel> userModelRepository =
	GsonModelRepository.builder(UserModel.class)
	  .folder(folderPath.resolve("users")) // Este será el folder donde se guardarán los archivos
    .prettyPrinting(true) // Esto es opcional, depende de si quieres un formato bonito en el archivo
    .modelSerializer(UserModelCodec.Serializer.INSTANCE)
    .modelDeserializer(UserModelCodec.Deserializer.INSTANCE)
    .build(executor); // El executor es necesario para operaciones asíncronas.

Con caché

final AsyncModelRepository<UserModel> userModelRepository =
	GsonModelRepository.builder(UserModel.class)
	  .folder(folderPath.resolve("users")) // Este será el folder donde se guardarán los archivos
    .prettyPrinting(true) // Esto es opcional, depende de si quieres un formato bonito en el archivo
    .modelSerializer(UserModelCodec.Serializer.INSTANCE)
    .modelDeserializer(UserModelCodec.Deserializer.INSTANCE)
    .buildCached(executor, LocalModelRepository.concurrent() /* Este es el repositorio que funcionará como caché */);

Resultado

folder/users/someId.json

{
	"id": "someId",
	"name": "Angel Miranda",
	"age": 18,
	"birthday": 1088150036 // Almacena únicamente el timestamp de la fecha
}