1 package com.vladmihalcea.hibernate.type.basic;
2
3 import com.vladmihalcea.hibernate.type.util.Configuration;
4 import com.vladmihalcea.hibernate.util.ReflectionUtils;
5 import org.hibernate.HibernateException;
6 import org.hibernate.engine.spi.SharedSessionContractImplementor;
7 import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
8
9 import java.sql.PreparedStatement;
10 import java.sql.SQLException;
11 import java.sql.Types;
12 import java.util.Properties;
13
14 /**
15  * Maps an {@link Enum} to a PostgreSQL ENUM column type.
16  * <p>
17  * For more details about how to use it, check out <a href="https://vladmihalcea.com/the-best-way-to-map-an-enum-type-with-jpa-and-hibernate/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
18  *
19  * @author Vlad Mihalcea
20  */

21 public class PostgreSQLEnumType extends org.hibernate.type.EnumType {
22
23     public static final PostgreSQLEnumType INSTANCE = new PostgreSQLEnumType();
24
25     private final Configuration configuration;
26
27     /**
28      * Initialization constructor taking the default {@link Configuration} object.
29      */

30     public PostgreSQLEnumType() {
31         this(Configuration.INSTANCE);
32     }
33
34     /**
35      * Initialization constructor taking a custom {@link Configuration} object.
36      *
37      * @param configuration custom {@link Configuration} object.
38      */

39     public PostgreSQLEnumType(Configuration configuration) {
40         this.configuration = configuration;
41     }
42
43     /**
44      * Initialization constructor taking the {@link Class}.
45      *
46      * @param enumClass The enum type
47      */

48     public PostgreSQLEnumType(Class<? extends Enum> enumClass) {
49         this();
50
51         Class typeConfigurationClass = ReflectionUtils.getClassOrNull("org.hibernate.type.spi.TypeConfiguration");
52
53         if(typeConfigurationClass != null) {
54             Object typeConfiguration = ReflectionUtils.newInstance(typeConfigurationClass);
55
56             Class enumJavaTypeDescriptorClass = ReflectionUtils.getClassOrNull("org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor");
57
58             Object enumJavaTypeDescriptor = ReflectionUtils.newInstance(enumJavaTypeDescriptorClass, new Object[] {enumClass}, new Class[]{enumClass.getClass()});
59
60             Object javaTypeDescriptorRegistry = ReflectionUtils.invokeGetter(typeConfiguration, "javaTypeDescriptorRegistry");
61
62             ReflectionUtils.invokeMethod(
63                 javaTypeDescriptorRegistry,
64                 ReflectionUtils.getMethod(javaTypeDescriptorRegistry, "addDescriptor", JavaTypeDescriptor.class),
65                 enumJavaTypeDescriptor
66             );
67
68             ReflectionUtils.invokeSetter(this"typeConfiguration", typeConfiguration);
69         }
70
71         Properties properties = new Properties();
72         properties.setProperty("enumClass", enumClass.getName());
73         properties.setProperty("useNamed", Boolean.TRUE.toString());
74         setParameterValues(properties);
75     }
76
77     public void nullSafeSet(
78             PreparedStatement st,
79             Object value,
80             int index,
81             SharedSessionContractImplementor session)
82             throws HibernateException, SQLException {
83         st.setObject(index, value != null ? ((Enum) value).name() : null, Types.OTHER);
84     }
85
86     @Override
87     public int[] sqlTypes() {
88         return new int[]{Types.VARCHAR};
89     }
90 }
91