Aquest inici de setmana me l’he passat mirant de refer una part de l’aplicació que mantinc. Havia d’automatitzar un procés que ara els usuaris han de fer manualment i que molts no recorden o no saben que han de fer. Aquest pas implica, entre altres coses, muntar els PDF als que feia cita a l’entrada anterior.
La generació d’aquests documents és relativament lenta; actualment cal esperar uns cinc segons aproximadament. Aquest temps avui dia és inacceptable en entorns web, de manera que aquest procés de regeneració del document (que abans es feia puntualment) no es pot executar cada cop que l’usuari demana descarregar-se el PDF. Per tant, el que es fa es servir una versió generada prèviament mentre les dades que nodreixen el document no hagin canviat.
Necessitava una manera de comparar les dades del document que s’havia generat anteriorment amb les dades actuals, per determinar en quin moment calia refer aquests PDF. Entre altres problemes, les dades necessàries per muntar els PDF provenen de quatre orígens de dades diferents; controlar en aquests orígens de dades quan es produeix un canvi és, a la pràctica, impossible.
Després de pensar una mica, he cregut que la millor opció (si més no, de moment) és fer ús del mecanisme de serialització que incorpora Java. Totes les dades que fan falta per muntar aquest document acaben formant part d’ún únic objecte, així que serialitzant aquest objecte cap a una cadena de caràcters i, tot seguit, obtenint-ne el seu valor hash, acabem treballant amb un identificador únic fàcil d’emmagatzemar (és un nombre enter). La teoria diu que si el valor de qualsevol dada d’aquest objecte canvia, el valor hash de l’objecte també ho fa. Realment això és així, però m’he trobat amb un gotcha. Les dades eren les mateixes en els dos objectes, ho havia comprovat amb traces, però el procés sempre regenerava els documents perquè els codis hash diferien.
Per què?
Degut a la multitud d’orígens de dades i d’una sèrie d’incompatibilitats, havia hagut de modificar unes llistes per eliminar uns objectes que venien sense dades, i que en la versió original del document no hi eren. Per posar un exemple, en la versió original tenia un llistat com ara 1, 2, 3, 4, 5 i les dades amb les que comparava tenia un llistat de l’estil 1, 2, 3, 0, 4, 5. El que feia era eliminar el zero, de manera que la llista tornava a quedar en 1, 2, 3, 4, 5. Però així i tot, els codis hash no coincidien.
Després de pensar-ho una mica, he trobat l’origen de l’errada. Al tenir originalment la llista amb sis elements, la llista no era exactament igual a la original, tot i que els elements que contenia sí que ho eren. En inicialitzar-se amb sis elements, l’array intern que emmagatzema les dades s’inicialitzava amb una capacitat de sis elements, i en esborrar el que sobrava, aquesta capacitat continuava en sis elements, mentre que originalment aquesta llista tenia una capacitat de cinc elements. Això és una diferència, i per tant, els codis hash difereixen.
La solució ha estat crear una llista nova a partir de la llista modificada. D’aquesta manera la capacitat i la resta de dades internes de la llista són idèntiques, i els codis hash són iguals.
He fet un petit codi font de prova que mostra el problema i la solució.
Conclusió: Les meves dades no són les dades.