Domanda

Attualmente sto lavorando a un progetto che deve persistere qualsiasi tipo di oggetto (di cui non abbiamo alcun controllo sull'implementazione) in modo che questi oggetti possano essere recuperati in seguito.

Non possiamo implementare un ORM perché non possiamo limitare gli utenti della nostra libreria in fase di sviluppo.

La nostra prima alternativa è stata quella di serializzarlo con la serializzazione predefinita Java, ma abbiamo avuto molti problemi a recuperare gli oggetti quando gli utenti hanno iniziato a passare diverse versioni dello stesso oggetto (gli attributi hanno cambiato tipi, nomi, ...).

Abbiamo provato con la classe XMLEncoder (trasforma un oggetto in un XML), ma abbiamo scoperto che manca una funzionalità (non supporta Enums per esempio).

Infine, abbiamo anche provato JAXB ma questo impone ai nostri utenti di annotare le loro classi.

Qualche buona alternativa?

È stato utile?

Soluzione

La cosa più semplice da fare è ancora usare la serializzazione, IMO, ma mettere più pensiero nella forma serializzata delle classi (che dovresti comunque fare davvero). Ad esempio:

  1. Definire esplicitamente SerialUID.
  2. Definisci il tuo modulo serializzato ove appropriato.

Il modulo serializzato fa parte dell'API della classe e un attento pensiero dovrebbe essere messo nella sua progettazione.

Non entrerò in molti dettagli, dato che praticamente tutto ciò che ho detto proviene da Effective Java. Ti farò invece riferimento ad esso, in particolare i capitoli sulla serializzazione. Ti avverte di tutti i problemi che stai riscontrando e fornisce soluzioni adeguate al problema:

http://www.amazon.com/Effective-Java-2nd-Joshua- Bloch / dp / 0321356683


Detto questo, se stai ancora considerando un approccio di non serializzazione, eccone un paio:

Marshalling XML

Come molti hanno sottolineato è un'opzione, ma penso che incontrerai ancora gli stessi problemi con la retrocompatibilità. Tuttavia, con il marshalling XML, si spera di prenderli subito, poiché alcuni framework potrebbero fare alcuni controlli durante l'inizializzazione.

Conversione da / a YAML

Questa è un'idea con cui ho giocato, ma mi è piaciuto molto il formato YAML (almeno come un formato personalizzato ToString ()). Ma davvero, l'unica differenza per te è che dovresti eseguire il marshalling su YAML anziché su XML. L'unico vantaggio è che YAML è leggermente più leggibile dall'uomo rispetto a XML. Si applicano le stesse restrizioni.

Altri suggerimenti

È il 2011 e in un progetto di servizi Web REST di livello commerciale utilizziamo i seguenti serializzatori per offrire ai clienti una varietà di tipi di media:

  • XStream (per XML ma non per JSON)
  • Jackson (per JSON)
  • Kryo (un formato di serializzazione binario veloce e compatto)
  • Smile (un formato binario fornito con Jackson 1.6 e versioni successive).
  • Serializzazione di oggetti Java.

Di recente abbiamo sperimentato altri serializzatori:

  • SimpleXML sembra solido, funziona a una velocità doppia rispetto a XStream, ma richiede un po 'troppa configurazione per il nostro situazione.
  • YamlBeans ha avuto un paio di bug.
  • SnakeYAML presentava un bug minore relativo alle date.

Jackson JSON, Kryo e Jackson Smile erano tutti significativamente più veloci della buona vecchia serializzazione di oggetti Java, da circa 3 a 4,5 volte. XStream è lento. Ma queste sono tutte solide scelte a questo punto. Continueremo a monitorare gli altri tre.

http://x-stream.github.io/ è carino, per favore prendi un guardarlo! Molto conveniente

  

di quale implementazione non abbiamo alcun controllo

La soluzione è non farlo . Se non hai il controllo dell'implementazione di un tipo, non dovresti serializzarlo. Fine della storia. La serializzazione Java fornisce serialVersionUID specificamente per la gestione delle incompatibilità di serializzazione tra diverse versioni di un tipo. Se non controlli l'implementazione, non puoi essere sicuro che gli ID vengano modificati correttamente quando uno sviluppatore cambia una classe.

Prendi un semplice esempio di un 'Punto'. Può essere rappresentato da un sistema di coordinate cartesiane o polari. Sarebbe proibitivo per te costruire un sistema in grado di far fronte in modo dinamico a questo tipo di correzioni - deve davvero essere lo sviluppatore della classe che progetta la serializzazione.

In breve, il tuo design è sbagliato, non la tecnologia.

google ha ideato un protocollo binario - http://code.google.com/apis/ protocolbuffers / è più veloce, ha un payload più piccolo rispetto a XML - che altri hanno suggerito come alternativa.

Uno dei vantaggi dei buffer di protocollo è che può scambiare informazioni con C, C ++, python e java.

Prova a serializzare su json con Gson per esempio.

Anche una sostituzione drop-in di serializzazione JDK molto veloce: http://ruedigermoeller.github.io/fast-serialization/

Se la velocità di serializzazione è importante per te, esiste un benchmark completo dei serializzatori JVM qui:

Personalmente, utilizzo molto Fame , poiché presenta l'interoperabilità con Smalltalk (sia VW che Squeak) e Python. (Dichiarazione di non responsabilità, sono il principale collaboratore del progetto Fame.)

Forse Castor ?

Betwixt è una buona libreria per serializzare oggetti - ma non sarà un tipo automatico di cosa. Se il numero di oggetti che devi serializzare è relativamente fisso, questa potrebbe essere una buona opzione per te, ma se il tuo "cliente" ti lancerà continuamente nuove classi, potrebbe essere più sforzo di quanto valga la pena ( Sicuramente più semplice di XMLEncoder per tutti i casi speciali, tuttavia.

Un altro approccio è quello di richiedere al cliente di fornire i file .betwixt appropriati per tutti gli oggetti che gli vengono lanciati (il che riduce effettivamente la responsabilità nei loro confronti).

Lungo e breve - la serializzazione è difficile - non esiste un approccio completamente cerebrale. La serializzazione Java è la soluzione più vicina al cervello che abbia mai visto, ma come hai trovato, un uso errato del valore uid della versione può interromperlo. La serializzazione Java richiede anche l'uso dell'interfaccia marcatore "Serializable", quindi se non riesci a controllare la tua fonte, sei un po 'sfortunato su quella.

Se il requisito è veramente arduo come descrivi, potresti dover ricorrere a una sorta di BCE (modifica del codice byte) sugli oggetti / aspetti / qualunque cosa. Questo sta andando al di fuori del regno di un piccolo progetto di sviluppo, e nel regno di Hibernate, Casper o un ORM ....

Un'altra idea: utilizzare la cache. Le cache offrono un controllo, una scalabilità e una robustezza molto migliori per l'applicazione. Tuttavia, è ancora necessario serializzare, ma la gestione diventa molto più semplice con un framework di servizi di cache. La cache può essere mantenuta nella memoria, nel disco, nel database o nell'array - o in tutte le opzioni - con uno che è overflow, stand-by, failover per l'altro. Commons JCS ed Ehcache sono due implementazioni Java, quest'ultima è una soluzione aziendale gratuita fino a 32 GB di spazio di archiviazione (dichiarazione di non responsabilità: non lavoro per ehcache ;-)).

SBE è una libreria consolidata per una libreria di serializzazione veloce, basata su bytebuffer e capace di versioning. Tuttavia è un po 'difficile da usare in quanto è necessario scrivere classi di wrapper di lunghezza su di esso.

Alla luce delle sue carenze, di recente ho creato una libreria di serializzazione solo Java ispirata al protocollo SBE e FIX (protocollo del mercato finanziario comune per lo scambio di messaggi commerciali / quotazioni), che cerca di mantenere i vantaggi di entrambi mentre supera il loro debolezze. Puoi dare un'occhiata a https://github.com/iceberglet/anymsg

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top