Skip to content

Commit 3137c5f

Browse files
authored
Merge pull request eugenp#5438 from dev-chirag/master
BAEL-1708 Custom Types in Hibernate
2 parents 244d774 + 9a6ce97 commit 3137c5f

14 files changed

+883
-2
lines changed

hibernate5/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
<artifactId>mariaDB4j</artifactId>
4545
<version>${mariaDB4j.version}</version>
4646
</dependency>
47+
<dependency>
48+
<groupId>org.hibernate</groupId>
49+
<artifactId>hibernate-testing</artifactId>
50+
<version>5.2.2.Final</version>
51+
</dependency>
4752
</dependencies>
4853

4954
<build>
@@ -57,7 +62,7 @@
5762
</build>
5863

5964
<properties>
60-
<hibernate.version>5.3.2.Final</hibernate.version>
65+
<hibernate.version>5.3.6.Final</hibernate.version>
6166
<mysql.version>6.0.6</mysql.version>
6267
<mariaDB4j.version>2.2.3</mariaDB4j.version>
6368
<h2database.version>1.4.196</h2database.version>

hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.net.URL;
66
import java.util.Properties;
77

8+
import com.baeldung.hibernate.customtypes.LocalDateStringType;
9+
import com.baeldung.hibernate.customtypes.OfficeEmployee;
810
import com.baeldung.hibernate.entities.DeptEmployee;
911
import com.baeldung.hibernate.optimisticlocking.OptimisticLockingCourse;
1012
import com.baeldung.hibernate.optimisticlocking.OptimisticLockingStudent;
@@ -18,8 +20,10 @@
1820
import org.apache.commons.lang3.StringUtils;
1921
import org.hibernate.SessionFactory;
2022
import org.hibernate.boot.Metadata;
23+
import org.hibernate.boot.MetadataBuilder;
2124
import org.hibernate.boot.MetadataSources;
2225
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
26+
import org.hibernate.cfg.Configuration;
2327
import org.hibernate.service.ServiceRegistry;
2428

2529
import com.baeldung.hibernate.pojo.Course;
@@ -66,6 +70,7 @@ public static SessionFactory getSessionFactory(String propertyFileName) throws I
6670

6771
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
6872
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
73+
6974
metadataSources.addPackage("com.baeldung.hibernate.pojo");
7075
metadataSources.addAnnotatedClass(Employee.class);
7176
metadataSources.addAnnotatedClass(Phone.class);
@@ -102,8 +107,12 @@ private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry
102107
metadataSources.addAnnotatedClass(com.baeldung.hibernate.entities.Department.class);
103108
metadataSources.addAnnotatedClass(OptimisticLockingCourse.class);
104109
metadataSources.addAnnotatedClass(OptimisticLockingStudent.class);
110+
metadataSources.addAnnotatedClass(OfficeEmployee.class);
111+
112+
Metadata metadata = metadataSources.getMetadataBuilder()
113+
.applyBasicType(LocalDateStringType.INSTANCE)
114+
.build();
105115

106-
Metadata metadata = metadataSources.buildMetadata();
107116
return metadata.getSessionFactoryBuilder()
108117
.build();
109118

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.baeldung.hibernate.customtypes;
2+
3+
import java.util.Objects;
4+
5+
public class Address {
6+
7+
private String addressLine1;
8+
private String addressLine2;
9+
private String city;
10+
private String country;
11+
private int zipCode;
12+
13+
public String getAddressLine1() {
14+
return addressLine1;
15+
}
16+
17+
public String getAddressLine2() {
18+
return addressLine2;
19+
}
20+
21+
public String getCity() {
22+
return city;
23+
}
24+
25+
public String getCountry() {
26+
return country;
27+
}
28+
29+
public int getZipCode() {
30+
return zipCode;
31+
}
32+
33+
public void setAddressLine1(String addressLine1) {
34+
this.addressLine1 = addressLine1;
35+
}
36+
37+
public void setAddressLine2(String addressLine2) {
38+
this.addressLine2 = addressLine2;
39+
}
40+
41+
public void setCity(String city) {
42+
this.city = city;
43+
}
44+
45+
public void setCountry(String country) {
46+
this.country = country;
47+
}
48+
49+
public void setZipCode(int zipCode) {
50+
this.zipCode = zipCode;
51+
}
52+
53+
@Override
54+
public boolean equals(Object o) {
55+
if (this == o) return true;
56+
if (o == null || getClass() != o.getClass()) return false;
57+
Address address = (Address) o;
58+
return zipCode == address.zipCode &&
59+
Objects.equals(addressLine1, address.addressLine1) &&
60+
Objects.equals(addressLine2, address.addressLine2) &&
61+
Objects.equals(city, address.city) &&
62+
Objects.equals(country, address.country);
63+
}
64+
65+
@Override
66+
public int hashCode() {
67+
return Objects.hash(addressLine1, addressLine2, city, country, zipCode);
68+
}
69+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package com.baeldung.hibernate.customtypes;
2+
3+
import org.hibernate.HibernateException;
4+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
5+
import org.hibernate.type.IntegerType;
6+
import org.hibernate.type.StringType;
7+
import org.hibernate.type.Type;
8+
import org.hibernate.usertype.CompositeUserType;
9+
10+
import java.io.Serializable;
11+
import java.sql.PreparedStatement;
12+
import java.sql.ResultSet;
13+
import java.sql.SQLException;
14+
import java.sql.Types;
15+
import java.util.Objects;
16+
17+
public class AddressType implements CompositeUserType {
18+
19+
@Override
20+
public String[] getPropertyNames() {
21+
return new String[]{"addressLine1", "addressLine2",
22+
"city", "country", "zipcode"};
23+
}
24+
25+
@Override
26+
public Type[] getPropertyTypes() {
27+
return new Type[]{StringType.INSTANCE, StringType.INSTANCE,
28+
StringType.INSTANCE, StringType.INSTANCE, IntegerType.INSTANCE};
29+
}
30+
31+
@Override
32+
public Object getPropertyValue(Object component, int property) throws HibernateException {
33+
34+
Address empAdd = (Address) component;
35+
36+
switch (property) {
37+
case 0:
38+
return empAdd.getAddressLine1();
39+
case 1:
40+
return empAdd.getAddressLine2();
41+
case 2:
42+
return empAdd.getCity();
43+
case 3:
44+
return empAdd.getCountry();
45+
case 4:
46+
return Integer.valueOf(empAdd.getZipCode());
47+
}
48+
49+
throw new IllegalArgumentException(property +
50+
" is an invalid property index for class type " +
51+
component.getClass().getName());
52+
}
53+
54+
@Override
55+
public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
56+
57+
Address empAdd = (Address) component;
58+
59+
switch (property) {
60+
case 0:
61+
empAdd.setAddressLine1((String) value);
62+
case 1:
63+
empAdd.setAddressLine2((String) value);
64+
case 2:
65+
empAdd.setCity((String) value);
66+
case 3:
67+
empAdd.setCountry((String) value);
68+
case 4:
69+
empAdd.setZipCode((Integer) value);
70+
}
71+
72+
throw new IllegalArgumentException(property +
73+
" is an invalid property index for class type " +
74+
component.getClass().getName());
75+
76+
}
77+
78+
@Override
79+
public Class returnedClass() {
80+
return Address.class;
81+
}
82+
83+
@Override
84+
public boolean equals(Object x, Object y) throws HibernateException {
85+
if (x == y)
86+
return true;
87+
88+
if (Objects.isNull(x) || Objects.isNull(y))
89+
return false;
90+
91+
return x.equals(y);
92+
}
93+
94+
@Override
95+
public int hashCode(Object x) throws HibernateException {
96+
return x.hashCode();
97+
}
98+
99+
@Override
100+
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
101+
102+
Address empAdd = new Address();
103+
empAdd.setAddressLine1(rs.getString(names[0]));
104+
105+
if (rs.wasNull())
106+
return null;
107+
108+
empAdd.setAddressLine2(rs.getString(names[1]));
109+
empAdd.setCity(rs.getString(names[2]));
110+
empAdd.setCountry(rs.getString(names[3]));
111+
empAdd.setZipCode(rs.getInt(names[4]));
112+
113+
return empAdd;
114+
}
115+
116+
@Override
117+
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
118+
119+
if (Objects.isNull(value))
120+
st.setNull(index, Types.VARCHAR);
121+
else {
122+
123+
Address empAdd = (Address) value;
124+
st.setString(index, empAdd.getAddressLine1());
125+
st.setString(index + 1, empAdd.getAddressLine2());
126+
st.setString(index + 2, empAdd.getCity());
127+
st.setString(index + 3, empAdd.getCountry());
128+
st.setInt(index + 4, empAdd.getZipCode());
129+
}
130+
}
131+
132+
@Override
133+
public Object deepCopy(Object value) throws HibernateException {
134+
135+
if (Objects.isNull(value))
136+
return null;
137+
138+
Address oldEmpAdd = (Address) value;
139+
Address newEmpAdd = new Address();
140+
141+
newEmpAdd.setAddressLine1(oldEmpAdd.getAddressLine1());
142+
newEmpAdd.setAddressLine2(oldEmpAdd.getAddressLine2());
143+
newEmpAdd.setCity(oldEmpAdd.getCity());
144+
newEmpAdd.setCountry(oldEmpAdd.getCountry());
145+
newEmpAdd.setZipCode(oldEmpAdd.getZipCode());
146+
147+
return newEmpAdd;
148+
}
149+
150+
@Override
151+
public boolean isMutable() {
152+
return true;
153+
}
154+
155+
@Override
156+
public Serializable disassemble(Object value, SharedSessionContractImplementor session) throws HibernateException {
157+
return (Serializable) deepCopy(value);
158+
}
159+
160+
@Override
161+
public Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException {
162+
return deepCopy(cached);
163+
}
164+
165+
@Override
166+
public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner) throws HibernateException {
167+
return original;
168+
}
169+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.baeldung.hibernate.customtypes;
2+
3+
import org.hibernate.type.LocalDateType;
4+
import org.hibernate.type.descriptor.WrapperOptions;
5+
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
6+
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
7+
import org.hibernate.type.descriptor.java.MutabilityPlan;
8+
9+
import java.time.LocalDate;
10+
11+
public class LocalDateStringJavaDescriptor extends AbstractTypeDescriptor<LocalDate> {
12+
13+
public static final LocalDateStringJavaDescriptor INSTANCE = new LocalDateStringJavaDescriptor();
14+
15+
public LocalDateStringJavaDescriptor() {
16+
super(LocalDate.class, ImmutableMutabilityPlan.INSTANCE);
17+
}
18+
19+
@Override
20+
public String toString(LocalDate value) {
21+
return LocalDateType.FORMATTER.format(value);
22+
}
23+
24+
@Override
25+
public LocalDate fromString(String string) {
26+
return LocalDate.from(LocalDateType.FORMATTER.parse(string));
27+
}
28+
29+
@Override
30+
public <X> X unwrap(LocalDate value, Class<X> type, WrapperOptions options) {
31+
32+
if (value == null)
33+
return null;
34+
35+
if (String.class.isAssignableFrom(type))
36+
return (X) LocalDateType.FORMATTER.format(value);
37+
38+
throw unknownUnwrap(type);
39+
}
40+
41+
@Override
42+
public <X> LocalDate wrap(X value, WrapperOptions options) {
43+
if (value == null)
44+
return null;
45+
46+
if(String.class.isInstance(value))
47+
return LocalDate.from(LocalDateType.FORMATTER.parse((CharSequence) value));
48+
49+
throw unknownWrap(value.getClass());
50+
}
51+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.baeldung.hibernate.customtypes;
2+
3+
import org.hibernate.dialect.Dialect;
4+
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
5+
import org.hibernate.type.DiscriminatorType;
6+
import org.hibernate.type.descriptor.java.LocalDateJavaDescriptor;
7+
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
8+
9+
import java.time.LocalDate;
10+
11+
public class LocalDateStringType extends AbstractSingleColumnStandardBasicType<LocalDate> implements DiscriminatorType<LocalDate> {
12+
13+
public static final LocalDateStringType INSTANCE = new LocalDateStringType();
14+
15+
public LocalDateStringType() {
16+
super(VarcharTypeDescriptor.INSTANCE, LocalDateStringJavaDescriptor.INSTANCE);
17+
}
18+
19+
@Override
20+
public String getName() {
21+
return "LocalDateString";
22+
}
23+
24+
@Override
25+
public LocalDate stringToObject(String xml) throws Exception {
26+
return fromString(xml);
27+
}
28+
29+
@Override
30+
public String objectToSQLString(LocalDate value, Dialect dialect) throws Exception {
31+
return '\'' + toString(value) + '\'';
32+
}
33+
34+
}

0 commit comments

Comments
 (0)