След много ровене в изходния код на Hibernate и PostgreSQL JDBC драйвера успях да намеря основната причина за проблема. В крайна сметка методът write() на BlobOutputStream (осигурен от JDBC драйвера) се извиква, за да запише съдържанието на Clob в базата данни. Този метод изглежда така:
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());
}
}
Този метод приема „int“ (32 бита/4 байта) като аргумент и го преобразува в „байт“ (8 бита/1 байт), ефективно губейки 3 байта информация. Представянията на низове в Java са UTF-16 кодирани, което означава, че всеки знак е представен от 16 бита/2 байта. Еврознакът има int стойност 8364. След преобразуване в байт остава стойност 172 (в октетно представяне 254).
Не съм сигурен сега какво е най-доброто решение на този проблем. IMHO JDBC драйверът трябва да отговаря за кодирането/декодирането на символите на Java UTF-16 до каквото кодиране се нуждае базата данни. Въпреки това не виждам никакви възможности за настройка в кода на JDBC драйвера, за да променя поведението му (и не искам да пиша и поддържам свой собствен код на JDBC драйвер).
Затова разширих Hibernate с персонализиран ClobType и успях да преобразувам символите UTF-16 в UTF-8, преди да пиша в базата данни и обратно, когато извличам Clob.
Решенията са твърде големи за просто поставяне в този отговор. Ако проявявате интерес, пишете ми и аз ще ви го изпратя.
Наздраве, Франк