CharacterType presented in this answer is available through the hibernate-types project, so there is no need to write it yourself.
For more details about using the CharacterType directly, check out this article .
First you need to define ImmutableType :
public abstract class ImmutableType<T> implements UserType { private final Class<T> clazz; protected ImmutableType(Class<T> clazz) { this.clazz = clazz; } @Override public Object nullSafeGet( ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { return get(rs, names, session, owner); } @Override public void nullSafeSet( PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException { set(st, clazz.cast(value), index, session); } protected abstract T get( ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException; protected abstract void set( PreparedStatement st, T value, int index, SharedSessionContractImplementor session) throws SQLException; @Override public Class<T> returnedClass() { return clazz; } @Override public boolean equals(Object x, Object y) { return Objects.equals(x, y); } @Override public int hashCode(Object x) { return x.hashCode(); } @Override public Object deepCopy(Object value) { return value; } @Override public boolean isMutable() { return false; } @Override public Serializable disassemble(Object o) { return (Serializable) o; } @Override public Object assemble( Serializable cached, Object owner) { return cached; } @Override public Object replace( Object o, Object target, Object owner) { return o; } }
Now we can move on to defining the actual CharacterType :
public class CharacterType extends ImmutableType<Character> { public CharacterType() { super(Character.class); } @Override public int[] sqlTypes() { return new int[]{Types.CHAR}; } @Override public Character get( ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { String value = rs.getString(names[0]); return (value != null && value.length() > 0) ? value.charAt(0) : null; } @Override public void set( PreparedStatement st, Character value, int index, SharedSessionContractImplementor session) throws SQLException { if (value == null) { st.setNull(index, Types.CHAR); } else { st.setString(index, String.valueOf(value)); } } }
An entity mapping is as follows:
@Entity(name = "Event") @Table(name = "event") public class Event { @Id @GeneratedValue private Long id; @Type(type = "com.vladmihalcea.book.hpjp.hibernate.type.CharacterType") @Column(name = "event_type") private Character type; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Character getType() { return type; } public void setType(Character type) { this.type = type; } }
And let's say we have these table rows:
INSERT INTO event (id, event_type) VALUES (1, 'abc'); INSERT INTO event (id, event_type) VALUES (2, ''); INSERT INTO event (id, event_type) VALUES (3, 'b');
When reading all entities:
doInJPA(entityManager -> { List<Event> events = entityManager.createQuery( "select e from Event e", Event.class) .getResultList(); for(Event event : events) { LOGGER.info("Event type: {}", event.getType()); } });
You will get the expected result:
Event type: a Event type: Event type: b
Check out the source code on GitHub .