From 3bf380a464dae6907c02ac9fb40fcbf122d443e8 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Sun, 2 May 2021 14:16:48 +0300 Subject: [PATCH 1/6] BAEL-4921 - Mapping Arrays with Hibernate --- persistence-modules/hibernate-mapping/pom.xml | 13 ++ .../arraymapping/CustomIntegerArrayType.java | 85 +++++++++++ .../arraymapping/CustomStringArrayType.java | 85 +++++++++++ .../arraymapping/HibernateSessionUtil.java | 61 ++++++++ .../baeldung/hibernate/arraymapping/User.java | 82 +++++++++++ .../CustomArrayTypeMappingUnitTest.java | 134 ++++++++++++++++++ .../resources/hibernate_postgres.properties | 14 ++ 7 files changed, 474 insertions(+) create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java create mode 100644 persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java create mode 100644 persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml index ebc854a621..2b33317e4a 100644 --- a/persistence-modules/hibernate-mapping/pom.xml +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -13,11 +13,22 @@ + + org.postgresql + postgresql + ${postgresql.version} + test + org.hibernate hibernate-core ${hibernate.version} + + com.vladmihalcea + hibernate-types-52 + ${hibernate-types.version} + org.assertj assertj-core @@ -65,7 +76,9 @@ + 42.2.20 5.4.12.Final + 2.10.4 3.8.0 6.0.16.Final 3.0.1-b11 diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java new file mode 100644 index 0000000000..c9b5cd5bb2 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomIntegerArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return Integer[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof Integer[] && y instanceof Integer[]) { + return Arrays.deepEquals((Integer[])x, (Integer[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((Integer[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("int", (Integer[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + Integer[] a = (Integer[])value; + return Arrays.copyOf(a, a.length); + } + + @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; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java new file mode 100644 index 0000000000..a6a66db127 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomStringArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return String[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof String[] && y instanceof String[]) { + return Arrays.deepEquals((String[])x, (String[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((String[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("text", (String[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + String[] a = (String[])value; + return Arrays.copyOf(a, a.length); + } + + @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; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java new file mode 100644 index 0000000000..dc3ec93a9d --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java @@ -0,0 +1,61 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.ServiceRegistry; + +import com.baeldung.hibernate.arraymapping.User; + +public class HibernateSessionUtil { + + private static SessionFactory sessionFactory; + private static String PROPERTY_FILE_NAME; + + public static SessionFactory getSessionFactory() throws IOException { + return getSessionFactory(null); + } + + public static SessionFactory getSessionFactory(String propertyFileName) throws IOException { + PROPERTY_FILE_NAME = propertyFileName; + if (sessionFactory == null) { + ServiceRegistry serviceRegistry = configureServiceRegistry(); + sessionFactory = makeSessionFactory(serviceRegistry); + } + return sessionFactory; + } + + private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) { + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + metadataSources.addAnnotatedClass(User.class); + + Metadata metadata = metadataSources.buildMetadata(); + return metadata.getSessionFactoryBuilder() + .build(); + + } + + private static ServiceRegistry configureServiceRegistry() throws IOException { + Properties properties = getProperties(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate_postgres.properties")); + try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) { + properties.load(inputStream); + } + return properties; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java new file mode 100644 index 0000000000..018bedc349 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java @@ -0,0 +1,82 @@ +package com.baeldung.hibernate.arraymapping; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.annotations.Type; + +import com.vladmihalcea.hibernate.type.array.StringArrayType; + +import org.hibernate.annotations.*; + +@TypeDefs({ + @TypeDef( + name = "string-array", + typeClass = StringArrayType.class + ) +}) +@Entity +public class User { + + @Id + private Long id; + + private String name; + + @Column(columnDefinition = "text[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomStringArrayType") + private String[] roles; + + @Column(columnDefinition = "int[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomIntegerArrayType") + private Integer[] locations; + + @Type(type = "string-array") + @Column( + name = "phone_numbers", + columnDefinition = "text[]" + ) + private String[] phoneNumbers; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public Integer[] getLocations() { + return locations; + } + + public void setLocations(Integer[] locations) { + this.locations = locations; + } + + public String[] getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(String[] phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java new file mode 100644 index 0000000000..6fddd8546f --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java @@ -0,0 +1,134 @@ +package com.baeldung.hibernate.arraymapping; + +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +public class CustomArrayTypeMappingUnitTest { + + private Session session; + private Transaction transaction; + + @BeforeEach + public void setup() throws IOException { + try { + session = HibernateSessionUtil.getSessionFactory().openSession(); + transaction = session.beginTransaction(); + + bootstrapData(); + + } catch (HibernateException | IOException e) { + + } + } + + @AfterEach + public void cleanup() { + if (null != session) { + transaction.rollback(); + session.close(); + } + } + + @Test + public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() throws HibernateException, IOException { + if (null != session) { + User user = session.find(User.class, 1L); + + assertEquals("john", user.getName()); + assertEquals("superuser", user.getRoles()[0]); + assertEquals("admin", user.getRoles()[1]); + assertEquals(100, user.getLocations()[0]); + assertEquals(389, user.getLocations()[1]); + assertEquals("7000000000", user.getPhoneNumbers()[0]); + assertEquals("8000000000", user.getPhoneNumbers()[1]); + } + } + + @Test + public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = new User(); + user.setId(2L); + user.setName("smith"); + + String[] roles = {"admin", "employee"}; + user.setRoles(roles); + + Integer[] locations = {190, 578}; + user.setLocations(locations); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + + User userDBObj = session.find(User.class, 2L); + + assertEquals("smith", userDBObj.getName()); + assertEquals("admin", userDBObj.getRoles()[0]); + assertEquals(578, userDBObj.getLocations()[1]); + } + } + + @Test + public void givenArrayMapping_whenArrayIsUpdated_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = session.find(User.class, 1L); + + String[] updatedRoles = {"superuser", "superadmin"}; + String[] updatedPhoneNumbers = {"9000000000"}; + + user.setRoles(updatedRoles); + user.setPhoneNumbers(updatedPhoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + User userDBObj = session.find(User.class, 1L); + + assertEquals("john", userDBObj.getName()); + assertEquals("superadmin", userDBObj.getRoles()[1]); + assertEquals("9000000000", userDBObj.getPhoneNumbers()[0]); + } + } + + public void bootstrapData() { + session.createQuery("delete from User").executeUpdate(); + + User user = new User(); + user.setId(1L); + user.setName("john"); + + String[] roles = {"superuser", "admin"}; + user.setRoles(roles); + + Integer[] locations = {100, 389}; + user.setLocations(locations); + + String[] phoneNumbers = {"7000000000", "8000000000"}; + user.setPhoneNumbers(phoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties new file mode 100644 index 0000000000..72e3dcd781 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties @@ -0,0 +1,14 @@ +hibernate.connection.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/postgres +hibernate.connection.username=web +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=none + +hibernate.c3p0.min_size=5 +hibernate.c3p0.max_size=20 +hibernate.c3p0.acquire_increment=5 +hibernate.c3p0.timeout=1800 From bb80ed7329708240b2c341f043fd39fb44ac618d Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Sun, 2 May 2021 14:16:48 +0300 Subject: [PATCH 2/6] BAEL-4921 - Mapping Arrays with Hibernate --- persistence-modules/hibernate-mapping/pom.xml | 13 ++ .../arraymapping/CustomIntegerArrayType.java | 85 +++++++++++ .../arraymapping/CustomStringArrayType.java | 85 +++++++++++ .../arraymapping/HibernateSessionUtil.java | 61 ++++++++ .../baeldung/hibernate/arraymapping/User.java | 82 +++++++++++ .../CustomArrayTypeMappingUnitTest.java | 134 ++++++++++++++++++ .../resources/hibernate_postgres.properties | 14 ++ 7 files changed, 474 insertions(+) create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java create mode 100644 persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java create mode 100644 persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java create mode 100644 persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml index ebc854a621..2b33317e4a 100644 --- a/persistence-modules/hibernate-mapping/pom.xml +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -13,11 +13,22 @@ + + org.postgresql + postgresql + ${postgresql.version} + test + org.hibernate hibernate-core ${hibernate.version} + + com.vladmihalcea + hibernate-types-52 + ${hibernate-types.version} + org.assertj assertj-core @@ -65,7 +76,9 @@ + 42.2.20 5.4.12.Final + 2.10.4 3.8.0 6.0.16.Final 3.0.1-b11 diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java new file mode 100644 index 0000000000..c9b5cd5bb2 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomIntegerArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return Integer[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof Integer[] && y instanceof Integer[]) { + return Arrays.deepEquals((Integer[])x, (Integer[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((Integer[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("int", (Integer[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + Integer[] a = (Integer[])value; + return Arrays.copyOf(a, a.length); + } + + @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; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java new file mode 100644 index 0000000000..a6a66db127 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomStringArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return String[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof String[] && y instanceof String[]) { + return Arrays.deepEquals((String[])x, (String[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((String[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("text", (String[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + String[] a = (String[])value; + return Arrays.copyOf(a, a.length); + } + + @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; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java new file mode 100644 index 0000000000..dc3ec93a9d --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java @@ -0,0 +1,61 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.ServiceRegistry; + +import com.baeldung.hibernate.arraymapping.User; + +public class HibernateSessionUtil { + + private static SessionFactory sessionFactory; + private static String PROPERTY_FILE_NAME; + + public static SessionFactory getSessionFactory() throws IOException { + return getSessionFactory(null); + } + + public static SessionFactory getSessionFactory(String propertyFileName) throws IOException { + PROPERTY_FILE_NAME = propertyFileName; + if (sessionFactory == null) { + ServiceRegistry serviceRegistry = configureServiceRegistry(); + sessionFactory = makeSessionFactory(serviceRegistry); + } + return sessionFactory; + } + + private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) { + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + metadataSources.addAnnotatedClass(User.class); + + Metadata metadata = metadataSources.buildMetadata(); + return metadata.getSessionFactoryBuilder() + .build(); + + } + + private static ServiceRegistry configureServiceRegistry() throws IOException { + Properties properties = getProperties(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate_postgres.properties")); + try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) { + properties.load(inputStream); + } + return properties; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java new file mode 100644 index 0000000000..018bedc349 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java @@ -0,0 +1,82 @@ +package com.baeldung.hibernate.arraymapping; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.annotations.Type; + +import com.vladmihalcea.hibernate.type.array.StringArrayType; + +import org.hibernate.annotations.*; + +@TypeDefs({ + @TypeDef( + name = "string-array", + typeClass = StringArrayType.class + ) +}) +@Entity +public class User { + + @Id + private Long id; + + private String name; + + @Column(columnDefinition = "text[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomStringArrayType") + private String[] roles; + + @Column(columnDefinition = "int[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomIntegerArrayType") + private Integer[] locations; + + @Type(type = "string-array") + @Column( + name = "phone_numbers", + columnDefinition = "text[]" + ) + private String[] phoneNumbers; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public Integer[] getLocations() { + return locations; + } + + public void setLocations(Integer[] locations) { + this.locations = locations; + } + + public String[] getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(String[] phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java new file mode 100644 index 0000000000..02d9dbc59c --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java @@ -0,0 +1,134 @@ +package com.baeldung.hibernate.arraymapping; + +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +public class CustomArrayTypeMappingUnitTest { + + private Session session; + private Transaction transaction; + + @BeforeEach + public void setup() throws IOException { + try { + session = HibernateSessionUtil.getSessionFactory().openSession(); + transaction = session.beginTransaction(); + + bootstrapData(); + + } catch (HibernateException | IOException e) { + System.out.println("Can't connect to a PostgreSQL DB"); + } + } + + @AfterEach + public void cleanup() { + if (null != session) { + transaction.rollback(); + session.close(); + } + } + + @Test + public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() throws HibernateException, IOException { + if (null != session) { + User user = session.find(User.class, 1L); + + assertEquals("john", user.getName()); + assertEquals("superuser", user.getRoles()[0]); + assertEquals("admin", user.getRoles()[1]); + assertEquals(100, user.getLocations()[0]); + assertEquals(389, user.getLocations()[1]); + assertEquals("7000000000", user.getPhoneNumbers()[0]); + assertEquals("8000000000", user.getPhoneNumbers()[1]); + } + } + + @Test + public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = new User(); + user.setId(2L); + user.setName("smith"); + + String[] roles = {"admin", "employee"}; + user.setRoles(roles); + + Integer[] locations = {190, 578}; + user.setLocations(locations); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + + User userDBObj = session.find(User.class, 2L); + + assertEquals("smith", userDBObj.getName()); + assertEquals("admin", userDBObj.getRoles()[0]); + assertEquals(578, userDBObj.getLocations()[1]); + } + } + + @Test + public void givenArrayMapping_whenArrayIsUpdated_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = session.find(User.class, 1L); + + String[] updatedRoles = {"superuser", "superadmin"}; + String[] updatedPhoneNumbers = {"9000000000"}; + + user.setRoles(updatedRoles); + user.setPhoneNumbers(updatedPhoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + User userDBObj = session.find(User.class, 1L); + + assertEquals("john", userDBObj.getName()); + assertEquals("superadmin", userDBObj.getRoles()[1]); + assertEquals("9000000000", userDBObj.getPhoneNumbers()[0]); + } + } + + public void bootstrapData() { + session.createQuery("delete from User").executeUpdate(); + + User user = new User(); + user.setId(1L); + user.setName("john"); + + String[] roles = {"superuser", "admin"}; + user.setRoles(roles); + + Integer[] locations = {100, 389}; + user.setLocations(locations); + + String[] phoneNumbers = {"7000000000", "8000000000"}; + user.setPhoneNumbers(phoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties new file mode 100644 index 0000000000..72e3dcd781 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties @@ -0,0 +1,14 @@ +hibernate.connection.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/postgres +hibernate.connection.username=web +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=none + +hibernate.c3p0.min_size=5 +hibernate.c3p0.max_size=20 +hibernate.c3p0.acquire_increment=5 +hibernate.c3p0.timeout=1800 From c764d5a8cb5478e6d0fc553d95127124a764d8d9 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Sun, 2 May 2021 14:21:35 +0300 Subject: [PATCH 3/6] A print statement added in the catch --- .../arraymapping/CustomArrayTypeMappingUnitTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java index 0cada05fd6..02d9dbc59c 100644 --- a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java @@ -27,11 +27,7 @@ public class CustomArrayTypeMappingUnitTest { bootstrapData(); } catch (HibernateException | IOException e) { -<<<<<<< HEAD System.out.println("Can't connect to a PostgreSQL DB"); -======= - ->>>>>>> 55e039bd3c7469ff8afa3183fb8d842489eb3634 } } From 735a9e93601d78d58ca948272ce7628cccce51a7 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Tue, 4 May 2021 06:46:34 +0300 Subject: [PATCH 4/6] BAEL-4921- fixed review comments --- .../hibernate/arraymapping/CustomIntegerArrayType.java | 4 ++-- .../hibernate/arraymapping/CustomStringArrayType.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java index c9b5cd5bb2..233bb95dc1 100644 --- a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java @@ -40,14 +40,14 @@ public class CustomIntegerArrayType implements UserType { @Override public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { + throws HibernateException, SQLException { Array array = rs.getArray(names[0]); return array != null ? array.getArray() : null; } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) - throws HibernateException, SQLException { + throws HibernateException, SQLException { if (value != null && st != null) { Array array = session.connection().createArrayOf("int", (Integer[])value); st.setArray(index, array); diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java index a6a66db127..7bd284def7 100644 --- a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java @@ -40,14 +40,14 @@ public class CustomStringArrayType implements UserType { @Override public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { + throws HibernateException, SQLException { Array array = rs.getArray(names[0]); return array != null ? array.getArray() : null; } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) - throws HibernateException, SQLException { + throws HibernateException, SQLException { if (value != null && st != null) { Array array = session.connection().createArrayOf("text", (String[])value); st.setArray(index, array); From cff01610d89129af16af836b28a0a5d90461a7a0 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Tue, 4 May 2021 06:49:55 +0300 Subject: [PATCH 5/6] BAEL-4921 - renamed to integration test --- ...UnitTest.java => CustomArrayTypeMappingIntegrationTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/{CustomArrayTypeMappingUnitTest.java => CustomArrayTypeMappingIntegrationTest.java} (98%) diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingIntegrationTest.java similarity index 98% rename from persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java rename to persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingIntegrationTest.java index 02d9dbc59c..eb34bcb6c5 100644 --- a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingIntegrationTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class CustomArrayTypeMappingUnitTest { +public class CustomArrayTypeMappingIntegrationTest { private Session session; private Transaction transaction; From b44d7b39a4db93ffd1ac2d84d76ad27c7c5b38d0 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Tue, 4 May 2021 06:49:55 +0300 Subject: [PATCH 6/6] BAEL-4921 - renamed to ArrayMappingIntegrationTest --- ...peMappingUnitTest.java => ArrayMappingIntegrationTest.java} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/{CustomArrayTypeMappingUnitTest.java => ArrayMappingIntegrationTest.java} (97%) diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java similarity index 97% rename from persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java rename to persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java index 02d9dbc59c..ba0ccc2aa2 100644 --- a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/CustomArrayTypeMappingUnitTest.java +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java @@ -1,6 +1,5 @@ package com.baeldung.hibernate.arraymapping; -import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; @@ -13,7 +12,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class CustomArrayTypeMappingUnitTest { +public class ArrayMappingIntegrationTest { private Session session; private Transaction transaction;