Dopo molte ricerche nel codice sorgente di Hibernate e nel driver JDBC di PostgreSQL, sono riuscito a trovare la causa principale del problema. Alla fine viene invocato il metodo write() del BlobOutputStream (fornito dal driver JDBC) per scrivere il contenuto del Clob nel database. Questo metodo è simile al seguente:
public void write(int b) throws java.io.IOException
{
checkClosed();
try
{
if (bpos >= bsize)
{
lo.write(buf);
bpos = 0;
}
buf[bpos++] = (byte)b;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
Questo metodo prende un 'int' (32 bit/4 byte) come argomento e lo converte in un 'byte' (8 bit/1 byte) perdendo di fatto 3 byte di informazioni. Le rappresentazioni di stringhe all'interno di Java sono codificate in UTF-16, il che significa che ogni carattere è rappresentato da 16 bit/2 byte. Il segno dell'euro ha il valore int 8364. Dopo la conversione in byte, il valore rimane 172 (nella rappresentazione dell'ottetto 254).
Non sono sicuro di quale sia ora la migliore soluzione a questo problema. IMHO il driver JDBC dovrebbe essere responsabile della codifica/decodifica dei caratteri Java UTF-16 in qualsiasi codifica necessaria al database. Tuttavia, non vedo alcuna possibilità di ritocco nel codice del driver JDBC per alterarne il comportamento (e non voglio scrivere e mantenere il mio codice del driver JDBC).
Pertanto, ho esteso Hibernate con un ClobType personalizzato e sono riuscito a convertire i caratteri UTF-16 in UTF-8 prima di scrivere nel database e viceversa durante il recupero del Clob.
Le soluzioni sono troppo grandi per incollare semplicemente in questa risposta. Se sei interessato, mandami un messaggio e te lo mando.
Ciao, Frank