Efter en masse grave rundt i kildekoden til Hibernate og PostgreSQL JDBC-driveren lykkedes det mig at finde årsagen til problemet. Til sidst aktiveres write()-metoden for BlobOutputStream (leveret af JDBC-driveren) for at skrive indholdet af Cloben ind i databasen. Denne metode ser sådan ud:
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());
}
}
Denne metode tager en 'int' (32 bit/4 bytes) som argument og konverterer den til en 'byte' (8 bit/1 byte), der effektivt mister 3 bytes information. Strengrepræsentationer i Java er UTF-16-kodede, hvilket betyder, at hvert tegn er repræsenteret af 16 bit/2 bytes. Eurotegnet har int-værdien 8364. Efter konvertering til byte forbliver værdien 172 (i oktetrepræsentation 254).
Jeg er ikke sikker på, hvad nu den bedste løsning er på dette problem. IMHO JDBC-driveren bør være ansvarlig for kodning/afkodning af Java UTF-16-tegnene til den kodning, databasen har brug for. Jeg kan dog ikke se nogen tweaking-muligheder i JDBC-driverkoden for at ændre dens adfærd (og jeg ønsker ikke at skrive og vedligeholde min egen JDBC-driverkode).
Derfor udvidede jeg Hibernate med en brugerdefineret ClobType og formåede at konvertere UTF-16-tegnene til UTF-8, før jeg skrev til databasen og omvendt, når jeg hentede Clob'en.
Løsningerne er for store til blot at indsætte dette svar. Hvis du er interesseret, så send mig en linje, og jeg sender den til dig.
Skål, Franck