Newsgroup: it.comp.java
Titolo: Implementare serializzazione [lunghetto...]

Salve a tutti.
Avrei un quesito da porre, penso sia una questione interessante.
Vorrei effettuare la serializzazione di oggetti senza però sfruttare i
meccanismi standard messi a disposizione dalla jvm, ma solo lato
software. E' tecnicamente possibile farlo per istanze di classi
qualsiasi?
Per classi qualsiasi intendo classi generiche senza "convenzioni"
speciali sul codice, quindi non dando per scontato che siano, ad
esempio, i vari metodi get per gli attributi oppure costruttori ad
hoc.
Mediante il medodo getDeclaredFields() della classe Class ho visto che
e' possibile scorrere tutti gli attributi, ma con le impostazioni
standard di sicurezza della jvm non e' possibile accedere al loro
contenuto (attributi private). Quindi l'unica soluzione che mi e'
venuta in mente e' presupporre la presenza dei metodi get per ogni
attributo (quindi classi ad hoc, non qualsiasi), oppure modificare la
politica di sicurezza della jvm per l'applicativo, anche se mi sembra
brutto.
E comunque c'è un altro problema. Ammettiamo di avere il permesso
dalla jvm di accedere ai membri private, tramite ricorsione posso
accedere a tutti gli attributi, ma come si fa per il processo inverso?
Supponiamo di avere una tabella che contiene i campi nome attributo -
valore, e di voler ricostruire l'oggetto. Se ho capito bene, guardando
le api, non so se mi sfugge qualcosa, l'unico modo per creare un
oggetto nuovo, anche con la riflessione, è invocare il corrispondente
costruttore.
La classe Class dispone del metodo newInstance(), che pero' utilizza
il costruttore vuoto per la creazione, dunque dovrei supporre la
presenza di un costruttore vuoto. Tramite il metodo
getDeclaredConstructors() posso accedere a tutti i costruttori, ma
come faccio a sapere quale è quello giusto, e chi mi dice che esista
un costruttore che inizializza tutti gli attributi? Ad esempio una
classe dato puo' avere un costruttore Dato(int id, int value), ma a
runtime come faccio a sapere che come primo parametro devo dargli l'id
e come secondo il valore, visto che l'unica informazione che posso
avere e' la presenza di un costruttore che accetta due int?
Per questo motivo, a meno che non mi smentiate, l'unica soluzione che
mi viene in mente e' porre delle convenzioni sul codice delle classi
che dovranno essere serializzate.
A tal fine, ho pensato che basterebbe disporre per ogni classe di un
array di stringhe che indica la lista degli attributi da serializzare,
per ogni attributo indicato deve esistere un corrispondente metodo
get, e deve esistere un costruttore che accetta in ingresso gli
attributi come indicati nell'array.
Ho pensato a due soluzioni: si potrebbe usare una annotation per la
classe del tipo @DataAttributes({"id","value"}), oppure implementare
una interfaccia che contiene un metodo dataAttributes() : String[] che
restituisce la lista degli attributi.
Secondo voi qual'è la soluzione migliore? La seconda consente di avere
un supertipo che identifica le classi serializzabili, comodo per un
uso coi generics, la prima mi sembra piu' "elegante".
Un altro tipo di soluzione potrebbe essere prevedere un metodo
serializeData() : byte[] che restituisce un array di byte con
l'oggetto serializzato, e relativo costruttore; oppure usare a tal
fine toString(), però non mi piace tanto perchè preferirei delegare le
operazioni di serializzazione al sistema e non all'applicazione.
Grazie dell'attenzione.
Marco

Marco
Scorpio.

 sta dietro alle tue intenzioni.
Purtroppo non posso dire molti dettagli. Il progetto a cui sto
lavorando e' una libreria, quindi non puo' sapere a priori le classi
degli oggetti che gli verranno dati in pasto dall'applicazione che ne
fara' uso.
Non e' possibile usare la serializzazione standard di java perche' il
formato di serializzazione e' fissato da specifica, in modo che sia
possibile accedere a tali dati anche usando altre piattaforme -
linguaggi.
Il dubbio architetturale che ho è se è necessario porre vincoli alle
classi che possono essere maneggiate da questa libreria, e quindi per
esempio ipotizzare la presenza di determinati costruttori (tipo quello
vuoto), oppure, tramite i meccanismi che mette a disposizione la
riflessione java, e' possibile serializzare e ricostruire oggetti
qualsiasi, tenendo presente che l'oggetto che voglio ricostruire
potrebbe anche non essere stato in origine un oggetto java.
La serializzazione, potendo accedere anche agli attributi private, non
e' più un problema.
Lo scoglio sta lato ricostruzione. Servirebbe un metodo, simile a
newInstance(), che genera un oggetto della classe specificata ma con
tutti gli attributi posti allo stato di default (null per i tipi
riferimento 0 per i primitivi), e senza passare per un costruttore
(anche quello vuoto, di cui non e' possibile presupporne l'esistenza).
Poi tramite riflessione questi attributi andranno riempiti dal
sistema.
Non c'è un "trucchetto", un modo per fare cio'?
Ciao ciao
Marco

 sta dietro alle tue intenzioni.
Purtroppo non posso dire molti dettagli. Il progetto a cui sto


Marco

 strada migliore...
Si, infatti.
La soluzione che penso verra' adottata e' definire una interfaccia
marker tipo "MySerialization", e sulla documentazione si indica: il
prodotto DEVE ricevere in ingresso solo oggetti di classi che
implementano quella interfaccia, una classe che implementa tale
interfaccia DEVE prevedere un costruttore senza parametri che non
solleva eccezioni non mette il thread in attesa o faccia cose strane,
e tutti i suoi attributi DEVONO essere o tipi primitivi o tipi che a
loro volta implementano l'interfaccia.
Di nuovo grazie per le dritte.
Ciao ciao
Marco

Di nuovo grazie per le dritte.
Figurati, e buon lavoro.
Scorpio.