Astratto
Un problema comune è archiviare oggetti (con un grafico) e caricarli di nuovo. Questo è facile finché la rappresentazione dell'oggetto memorizzata corrisponde al codice in esecuzione. Ma col passare del tempo, i requisiti cambiano e gli oggetti memorizzati non corrispondono più al codice. Gli oggetti memorizzati non dovrebbero perdere i loro dati e il codice nei client dovrebbe funzionare con gli ultimi modelli di oggetti.
Quindi una trasformazione deve avvenire in qualche modo tra il caricamento dei dati e la restituzione di un oggetto al client.
So che esistono alcune librerie come XStream, gson, protobuf e avro. Potrebbero caricare oggetti più vecchi, ma afaik ignora semplicemente i dati che non corrispondono più ai campi della classe (forse mi sono perso qualcosa).
(Quando parlo di memorizzazione e serializzazione non intendo il meccanismo di serializzazione incorporato di Java.)
Domanda
Quindi qual è la domanda? Ora sto facendo ricerche per un po 'di tempo e non sembra esistere una libreria che indirizzi questo problema (evoluzione della classe) senza perdita di dati. Spero di trovare un'altra soluzione funzionante o un'idea su come implementarla da solo qui.
Ho alcuni requisiti:
- Basato su file - Voglio poter archiviare l'oggetto serializzato sul disco
- Appendibile - Voglio aggiungere più oggetti a un file senza caricare l'intero file in memoria ancora e ancora
- Supporto per più versioni in un unico file: un file può contenere oggetti con versioni diverse (solo dello stesso tipo)
- Trasformazione: i dati devono essere accessibili utilizzando lo stesso tipo, anche se modificati tra.
- Generico - Il meccanismo stesso deve essere generico, quindi potrei usarlo per oggetti diversi (oggetti diversi non si mischiano in un file, solo versioni diverse di un tipo).
Sarebbe bello se il formato di memorizzazione fosse leggibile dall'uomo.
Gli oggetti già memorizzati non sono aggiornabili (almeno non senza grandi sforzi). Pensa a un archivio a lungo termine.
Esempio
Potrei dare un esempio per una migliore illustrazione. Supponiamo di avere due Pojos che vogliamo serializzare.
public class MyPojo {
String text;
Long number;
Integer[] values;
SubPojo pojo;
}
public class SubPojo {
List<String> items;
}
Nella prossima versione avremmo potuto rinominare un campo (testo e contenuto), aver cambiato un tipo (Intero [] - > Elenco) e aver trasformato un campo in Elenco (Sottopunto - > Elenco) dove il il campo precedente ora è il primo elemento della nuova lista (non perdere dati, semplicemente trasformando in nuova rappresentazione).
public class MyPojo {
String content;
Long number;
List<Integer> values;
List<SubPojo> pojo;
}
public class SubPojo {
List<String> items;
}
Alcuni pseudocodici su come il client potrebbe usare questo:
// Write
Serializer ser = new Serializer();
MyPojo pojo = new MyPojo();
pojo.xxx = ...; // set fields
ser.store(pojo, file, append);
// Read (a version later)
Serializer ser = new Serializer();
ser.registerTransformer(new TransformerV1ToV2());
List<MyPojo> pojos = ser.load(file);
Questo approccio presenta alcuni inconvenienti:
- Il trasformatore deve lavorare su un qualche tipo di formato intermedio (potrebbe essere il formato memorizzato di backup come json o xml)
- Non sai come fosse il formato della classe ad un certo punto nel tempo, dal momento che stai solo trasformando la versione precedente e la mappatura alla classe finale, rendendo difficile la ricerca di errori
- Prestazioni (a seconda di come avviene la trasformazione)