Efter mycket grävande i källkoden för Hibernate och PostgreSQL JDBC-drivrutinen lyckades jag hitta grundorsaken till problemet. Till slut anropas metoden write() för BlobOutputStream (som tillhandahålls av JDBC-drivrutinen) för att skriva innehållet i Cloben till databasen. Den här metoden ser ut så här:
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());
}
}
Denna metod tar en 'int' (32 bitar/4 byte) som argument och konverterar den till en 'byte' (8 bitar/1 byte) som effektivt förlorar 3 byte information. Strängrepresentationer inom Java är UTF-16-kodade, vilket innebär att varje tecken representeras av 16 bitar/2 byte. Eurotecknet har int-värdet 8364. Efter konvertering till byte finns värdet 172 kvar (i oktettrepresentation 254).
Jag är inte säker på vad som nu är den bästa lösningen på detta problem. IMHO JDBC-drivrutinen bör vara ansvarig för att koda/avkoda Java UTF-16-tecken till vilken kodning som helst som databasen behöver. Jag ser dock inga möjligheter att justera JDBC-drivrutinskoden för att ändra dess beteende (och jag vill inte skriva och underhålla min egen JDBC-drivrutinskod).
Därför utökade jag Hibernate med en anpassad ClobType och lyckades konvertera UTF-16-tecken till UTF-8 innan jag skrev till databasen och vice versa när jag hämtade Clob.
Lösningarna är för stora för att bara klistra in det här svaret. Om du är intresserad, skriv till mig så skickar jag den till dig.
Skål, Franck