Enterprise Java

Custom Boolean User Type with Hibernate JPA

The ANSI SQL 1999 standard introduced a BOOLEAN data type (although unfortunately only as an optional feature). But to date it still isn’t implemented by most major database systems. As a consequence boolean columns are implemented in various ways. E.g., CHAR columns containing ‘Y’ or ‘N’, or using BIT columns. Subsequently, there is no way for JPA to provide a standardized way of mapping an entity’s boolean fields onto database columns.

Hibernate offers a custom YesNoType for boolean implementations using CHAR(1) columns containing ‘Y’ or ’N’ characters. But for other practices you basically have to provide your own solution. Fortunately, Hibernate offers the possibility of creating your own custom UserType’s. In this blog entry I will give an example of one such custom Boolean UserType.

Recently, I’ve been confronted with a Dutch legacy database schema in which ‘Y’ (for yes) and ‘N’ (for no) are represented by ‘J’ (“ja”) and ‘N’ (“nee”), respectively. This ruled out using Hibernate’s YesNoType. Adding to the complexity was the fact that some of these columns were using CHAR(1) and others using CHAR(2) with a padded space – don’t ask why!

So I ended up writing a custom UserType that allowed me to basically convert the following…

The starting point

@Table(name = "FOO_BAR")
public class FooBar implements Serializable {
    @Column(name = "FOO_ INDICATOR")
    private String fooIndicator;
    @Column(name = "BAR_ INDICATOR", length = 2)
    private String barIndicator;
    // …


The desired situation

@Table(name = "FOO_BAR")
    @TypeDef(name = JaNeeType.NAME, typeClass = JaNeeType.class)
public class FooBar implements Serializable {
    @Column(name = "FOO_INDICATOR)
    @Type(type = JaNeeType.NAME)
    private Boolean fooIndicator;
    @Column(name = "BAR_INDICATOR", length = 2)
    @Type(type = JaNeeType.NAME, parameters = { @Parameter(name = "length", value = "2") })
    @Type(type = JaNeeType.NAME)
    private Boolean barIndicator;
    // …

Coding the custom type proved to be fairly straight forward. I just had to implement the interface org.hibernate.usertype.UserType. Dealing with the varying column lengths involved adding the ‘length’ parameter required implementing a second interface – org.hibernate.usertype.ParameterizedType.

Given below is what I did end up with.


package it.jdev.examples.persistence.hibernate;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 * A type that maps between {@link java.sql.Types#VARCHAR CHAR(1) or CHAR(2)} and {@link Boolean} (using "J " and "N ").
 * <p>
 * Optionally, a parameter "length" can be set that will result in right-padding with spaces up to the
 * specified length.
public class JaNeeType implements UserType, ParameterizedType {
    public static final String NAME = "ja_nee";
    private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    private int length = 1;
    public int[] sqlTypes() {
        return new int[] { Types.VARCHAR };
    public Class returnedClass() {
        return Boolean.class;
    public boolean equals(final Object x, final Object y) throws HibernateException {
        if (x == null || y == null) {
            return false;
        } else {
            return x.equals(y);
    public int hashCode(final Object x) throws HibernateException {
        assert (x != null);
        return x.hashCode();
    public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session, final Object owner) throws HibernateException, SQLException {
        final String s = rs.getString(names[0]);
        if (StringUtils.isBlank(s)) {
            return false;
        if ("J".equalsIgnoreCase(s.trim())) {
            return Boolean.TRUE;
        return Boolean.FALSE;
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index, final SessionImplementor session) throws HibernateException, SQLException {
        String s = Boolean.TRUE.equals(value) ? "J" : "N";
        if (this.length > 1) {
            s = StringUtils.rightPad(s, this.length);
        st.setString(index, s);
    public Object deepCopy(final Object value) throws HibernateException {
        return value;
    public boolean isMutable() {
        return true;
    public Serializable disassemble(final Object value) throws HibernateException {
        return (Serializable) value;
    public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
        return cached;
    public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
        return original;
    public void setParameterValues(final Properties parameters) {
        if (parameters != null && !parameters.isEmpty()) {
            final String lengthString = parameters.getProperty("length");
            try {
                if (StringUtils.isNotBlank(lengthString)) {
                    this.length = Integer.parseInt(lengthString);
            } catch (final NumberFormatException e) {
                LOGGER.error("Error parsing int " + lengthString, e);
Reference: Custom Boolean User Type with Hibernate JPA from our JCG partner Wim van Haaren at the JDev blog.

Want to know how to develop your skillset to become a Java Rockstar?

Join our newsletter to start rocking!

To get you started we give you our best selling eBooks for FREE!


1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design


and many more ....


Receive Java & Developer job alerts in your Area

I have read and agree to the terms & conditions


Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Newest Most Voted
Inline Feedbacks
View all comments
8 years ago

I think that the same result can be achieved using javax.persistence.AttributeConverter and javax.persistence.Converter (from JPA 2.1).

Back to top button