(Resolvido) Hibernate - StringIndexOutOfBoundsException, como resolver

Galera, alguém já passou pelo problema do StringIndexOutOfBoundsException no Hibernate?
Isso acontece quando tenho um campo char ou varchar que está em branco, na implementação do CharacterTypeDescriptor (que lança a exceção) está assim:

public <X> Character wrap(X value, WrapperOptions options) {
		if ( value == null ) {
			return null;
		}
		if ( Character.class.isInstance( value ) ) {
			return (Character) value;
		}
		if ( String.class.isInstance( value ) ) {
			final String str = (String) value;
			return Character.valueOf( str.charAt(0) );
		}
		if ( Number.class.isInstance( value ) ) {
			final Number nbr = (Number) value;
			return Character.valueOf( (char)nbr.shortValue() );
		}
		throw unknownWrap( value.getClass() );
	}

E o topo do StackTrace:

java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:695)
at org.hibernate.type.descriptor.java.CharacterTypeDescriptor.wrap(CharacterTypeDescriptor.java:79)
at org.hibernate.type.descriptor.java.CharacterTypeDescriptor.wrap(CharacterTypeDescriptor.java:33)

Alguém aí tem algum “workaround” pra esse problema? Tem inúmeros campos no banco de dados assim, e é completamente inviável mudar isso… Nessa 1 hora que to procurando isso na net vi falar de um cara que “sobrescreveu” esse CharacterTypeDescriptor, alguma idéia de como consigo isso no Hibernate?

Obrigado.

Você poderia mudar o mapeamento de Char para String, pois no banco esta mapeado como varchar. Não encontrei uma forme de sobrescrever o CharacterTypeDescriptor

No mapeamento já está “string”. Após pesquisar uma nas issues do Hibernate no JIRA achei isso:
https://hibernate.onjira.com/browse/HB-1355

O que me levou a solucionar o problema implementando um UserType, agora consigo tratar os casos de Strings em branco no banco de dados e fica aqui a solução para quem quiser:

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;

public class EmptyStringType implements UserType {

    private static final int[] SQL_TYPES = {Types.VARCHAR};

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Class returnedClass() {
        return String.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return x.equals(y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        String val = rs.getString(names[0]);
        if (val == null) {
            return null;
        }
        if (val.equals("")) {
            return null;
        }
        return val;
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
        } else {
            st.setString(index, value.equals("") ? " " : (String) value);
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        if (value == null) {
            return null;
        }
        return (String) value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }
}

Essa é a implementação do tipo que defini que agora aceita String’s em branco.
No caso, apenas isso não faz com que seja utilizado esse tipo, é necessário registrá-lo na configuração do Hibernate:

public class HibernateUtil {
//... Algum código aqui...

Configuration config = new Configuration();
        config.configure("hibernate.cfg.xml");
        config.registerTypeOverride(new EmptyStringType(), new String[]{"caminhoDosPacotesAteChegarOndeVoceColocouAClasse.EmptyStringType"});
        // no meu caso deixei assim (para não ter que ficar caçando todos esses mapeamentos, simplesmente os sobrescrevi)
        // config.registerTypeOverride(new EmptyStringType(), new String[]{"string", "java.lang.String", "java.lang.Character", "br.com.avance.util.Hibernate.EmptyStringType"});

// ... mais código a partir daqui.

}

Registrando o tipo você já pode utilizá-lo nos mapeamentos, e caso tenha sobrescrito, pode utilizar com qualquer chave que tenha sobrescrito ou adicionado.
Essa foi a minha implementação, creio que ainda preciso mudar bastante pois outros probleminhas podem aparecer (sistema legado é uma m…)
Mas fica a dica pra quem quiser, valeu.