Commit 257a3b7900bcb1ab50b2c99ad8e8edca31679b6f
1 parent
201450f1
Add json properties with hibernate UserType mapping to 'user' entity
Showing
7 changed files
with
161 additions
and
10 deletions
services/Common/src/main/java/de/bht/beuthbot/model/entities/User.java
@@ -7,5 +7,6 @@ public interface User extends Entity { | @@ -7,5 +7,6 @@ public interface User extends Entity { | ||
7 | 7 | ||
8 | String getFacebookUserId(); | 8 | String getFacebookUserId(); |
9 | String getTelegramUserId(); | 9 | String getTelegramUserId(); |
10 | - boolean isVegetarian(); | 10 | + <T extends Object> T getProperty(String propertyName, Class<T> propertyType); |
11 | + void setProperty(String propertyName, Object propertyValue); | ||
11 | } | 12 | } |
services/Global/build.gradle
@@ -15,6 +15,7 @@ dependencies { | @@ -15,6 +15,7 @@ dependencies { | ||
15 | "org.hibernate:hibernate-core:5.2.12.Final", | 15 | "org.hibernate:hibernate-core:5.2.12.Final", |
16 | "org.hibernate:hibernate-entitymanager:4.3.6.Final" | 16 | "org.hibernate:hibernate-entitymanager:4.3.6.Final" |
17 | 17 | ||
18 | + compile group: 'org.postgresql', name: 'postgresql', version: '9.3-1100-jdbc4' | ||
18 | 19 | ||
19 | providedCompile "org.slf4j:slf4j-api:1.7.25" | 20 | providedCompile "org.slf4j:slf4j-api:1.7.25" |
20 | 21 |
services/Global/src/main/java/de/bht/beuthbot/entities/EntityBase.java
1 | package de.bht.beuthbot.entities; | 1 | package de.bht.beuthbot.entities; |
2 | 2 | ||
3 | import de.bht.beuthbot.model.entities.Entity; | 3 | import de.bht.beuthbot.model.entities.Entity; |
4 | +import de.bht.beuthbot.persistence.JsonMapUserType; | ||
5 | +import org.hibernate.annotations.TypeDef; | ||
4 | 6 | ||
5 | import javax.persistence.*; | 7 | import javax.persistence.*; |
6 | import java.util.Date; | 8 | import java.util.Date; |
@@ -10,6 +12,8 @@ import java.util.Objects; | @@ -10,6 +12,8 @@ import java.util.Objects; | ||
10 | * Created by Benjamin Rühl on 19.11.2017. | 12 | * Created by Benjamin Rühl on 19.11.2017. |
11 | */ | 13 | */ |
12 | @MappedSuperclass | 14 | @MappedSuperclass |
15 | +@Access(AccessType.FIELD) | ||
16 | +@TypeDef(name = "JsonMapType", typeClass = JsonMapUserType.class) | ||
13 | public class EntityBase implements Entity { | 17 | public class EntityBase implements Entity { |
14 | 18 | ||
15 | @Id | 19 | @Id |
@@ -63,7 +67,7 @@ public class EntityBase implements Entity { | @@ -63,7 +67,7 @@ public class EntityBase implements Entity { | ||
63 | if (other.getId() == 0 && getId() == 0) | 67 | if (other.getId() == 0 && getId() == 0) |
64 | return super.equals(obj); | 68 | return super.equals(obj); |
65 | 69 | ||
66 | - return other.getId() == getId(); | 70 | + return Objects.equals(other.getId(), getId()); |
67 | } | 71 | } |
68 | 72 | ||
69 | @Override | 73 | @Override |
services/Global/src/main/java/de/bht/beuthbot/entities/User.java
1 | package de.bht.beuthbot.entities; | 1 | package de.bht.beuthbot.entities; |
2 | 2 | ||
3 | +import de.bht.beuthbot.persistence.JsonHelper; | ||
4 | +import org.hibernate.annotations.Type; | ||
5 | + | ||
3 | import javax.persistence.Entity; | 6 | import javax.persistence.Entity; |
4 | import javax.persistence.Table; | 7 | import javax.persistence.Table; |
8 | +import java.util.HashMap; | ||
9 | +import java.util.Map; | ||
5 | 10 | ||
6 | /** | 11 | /** |
7 | * Created by Benjamin Rühl on 19.11.2017. | 12 | * Created by Benjamin Rühl on 19.11.2017. |
@@ -12,7 +17,9 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | @@ -12,7 +17,9 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | ||
12 | 17 | ||
13 | private String facebookUserId; | 18 | private String facebookUserId; |
14 | private String telegramUserId; | 19 | private String telegramUserId; |
15 | - private boolean isVegetarian; | 20 | + |
21 | + @Type(type = "JsonMapType") | ||
22 | + private Map<String, String> additionalData = new HashMap<>(); | ||
16 | 23 | ||
17 | @Override | 24 | @Override |
18 | public String getFacebookUserId() { | 25 | public String getFacebookUserId() { |
@@ -25,8 +32,19 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | @@ -25,8 +32,19 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | ||
25 | } | 32 | } |
26 | 33 | ||
27 | @Override | 34 | @Override |
28 | - public boolean isVegetarian() { | ||
29 | - return isVegetarian; | 35 | + public <T extends Object> T getProperty(String propertyName, Class<T> propertyType) { |
36 | + String propertyValue = additionalData.getOrDefault(propertyName, null); | ||
37 | + | ||
38 | + if (propertyValue == null) | ||
39 | + return null; | ||
40 | + | ||
41 | + return (T) JsonHelper.fromJson(propertyValue, propertyType); | ||
42 | + } | ||
43 | + | ||
44 | + @Override | ||
45 | + public void setProperty(String propertyName, Object propertyValue) { | ||
46 | + String valueAsJson = JsonHelper.toJson(propertyValue, propertyValue.getClass()); | ||
47 | + additionalData.put(propertyName, valueAsJson); | ||
30 | } | 48 | } |
31 | 49 | ||
32 | public void setFacebookUserId(String facebookUserId) { | 50 | public void setFacebookUserId(String facebookUserId) { |
@@ -36,8 +54,4 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | @@ -36,8 +54,4 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U | ||
36 | public void setTelegramUserId(String telegramUserId) { | 54 | public void setTelegramUserId(String telegramUserId) { |
37 | this.telegramUserId = telegramUserId; | 55 | this.telegramUserId = telegramUserId; |
38 | } | 56 | } |
39 | - | ||
40 | - public void setVegetarian(boolean vegetarian) { | ||
41 | - this.isVegetarian = vegetarian; | ||
42 | - } | ||
43 | } | 57 | } |
services/Global/src/main/java/de/bht/beuthbot/persistence/JsonHelper.java
0 → 100644
1 | +package de.bht.beuthbot.persistence; | ||
2 | + | ||
3 | +import com.google.gson.Gson; | ||
4 | +import com.google.gson.GsonBuilder; | ||
5 | + | ||
6 | +/** | ||
7 | + * Created by Benjamin Rühl on 03.12.2017. | ||
8 | + * A simple wrapper around the json serializer to make sure the same serializer is used across different classes | ||
9 | + */ | ||
10 | +public class JsonHelper { | ||
11 | + | ||
12 | + private static final Gson gson = new GsonBuilder().serializeNulls().create(); | ||
13 | + | ||
14 | + public static Object fromJson(String json, Class sourceClass) { | ||
15 | + return gson.fromJson(json, sourceClass); | ||
16 | + } | ||
17 | + | ||
18 | + public static String toJson(Object source, Class sourceClass) { | ||
19 | + return gson.toJson(source, sourceClass); | ||
20 | + } | ||
21 | +} |
services/Global/src/main/java/de/bht/beuthbot/persistence/JsonMapUserType.java
0 → 100644
1 | +package de.bht.beuthbot.persistence; | ||
2 | + | ||
3 | +import org.hibernate.HibernateException; | ||
4 | +import org.hibernate.engine.spi.SharedSessionContractImplementor; | ||
5 | +import org.hibernate.internal.util.compare.EqualsHelper; | ||
6 | +import org.hibernate.type.SerializationException; | ||
7 | +import org.hibernate.usertype.UserType; | ||
8 | +import org.postgresql.util.PGobject; | ||
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.HashMap; | ||
16 | +import java.util.Map; | ||
17 | + | ||
18 | +/** | ||
19 | + * Created by Benjamin Rühl on 03.12.2017. | ||
20 | + * Custom Hibernate UserType for mapping json typed columns in postgres to java maps | ||
21 | + * @see <a href="http://vojtechruzicka.com/postgresqls-jsonb-type-mapping-using-hibernate/">vojtechruzicka.com</a> | ||
22 | + */ | ||
23 | +public class JsonMapUserType implements UserType { | ||
24 | + | ||
25 | + @Override | ||
26 | + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException { | ||
27 | + if (value == null) { | ||
28 | + st.setNull(index, Types.OTHER); | ||
29 | + } else { | ||
30 | + st.setObject(index, JsonHelper.toJson(value, Map.class), Types.OTHER); | ||
31 | + } | ||
32 | + } | ||
33 | + | ||
34 | + @Override | ||
35 | + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { | ||
36 | + PGobject o = (PGobject) rs.getObject(names[0]); | ||
37 | + if (o.getValue() != null) { | ||
38 | + return JsonHelper.fromJson(o.getValue(), Map.class); | ||
39 | + } | ||
40 | + | ||
41 | + return new HashMap<String, String>(); | ||
42 | + } | ||
43 | + | ||
44 | + @Override | ||
45 | + public Object deepCopy(Object originalValue) throws HibernateException { | ||
46 | + if (originalValue == null) { | ||
47 | + return null; | ||
48 | + } | ||
49 | + | ||
50 | + if (!(originalValue instanceof Map)) { | ||
51 | + return null; | ||
52 | + } | ||
53 | + | ||
54 | + Map<String, String> resultMap = new HashMap<>(); | ||
55 | + | ||
56 | + Map<?, ?> tempMap = (Map<?, ?>) originalValue; | ||
57 | + tempMap.forEach((key, value) -> resultMap.put((String) key, (String) value)); | ||
58 | + | ||
59 | + return resultMap; | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public Serializable disassemble(Object value) throws HibernateException { | ||
64 | + Object copy = deepCopy(value); | ||
65 | + | ||
66 | + if (copy instanceof Serializable) { | ||
67 | + return (Serializable) copy; | ||
68 | + } | ||
69 | + | ||
70 | + throw new SerializationException(String.format("Cannot serialize '%s', %s is not Serializable.", value, value.getClass()), null); | ||
71 | + } | ||
72 | + | ||
73 | + @Override | ||
74 | + public Object assemble(Serializable cached, Object owner) throws HibernateException { | ||
75 | + return deepCopy(cached); | ||
76 | + } | ||
77 | + | ||
78 | + @Override | ||
79 | + public Object replace(Object original, Object target, Object owner) throws HibernateException { | ||
80 | + return deepCopy(original); | ||
81 | + } | ||
82 | + | ||
83 | + @Override | ||
84 | + public boolean isMutable() { | ||
85 | + return true; | ||
86 | + } | ||
87 | + | ||
88 | + @Override | ||
89 | + public int hashCode(Object x) throws HibernateException { | ||
90 | + if (x == null) { | ||
91 | + return 0; | ||
92 | + } | ||
93 | + | ||
94 | + return x.hashCode(); | ||
95 | + } | ||
96 | + | ||
97 | + @Override | ||
98 | + public boolean equals(Object x, Object y) throws HibernateException { | ||
99 | + return EqualsHelper.equals(x, y); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public Class<?> returnedClass() { | ||
104 | + return Map.class; | ||
105 | + } | ||
106 | + | ||
107 | + @Override | ||
108 | + public int[] sqlTypes() { | ||
109 | + return new int[]{Types.JAVA_OBJECT}; | ||
110 | + } | ||
111 | +} |
services/Global/src/main/java/de/bht/beuthbot/persistence/UserManager.java
@@ -16,7 +16,6 @@ public class UserManager { | @@ -16,7 +16,6 @@ public class UserManager { | ||
16 | User user = new User(); | 16 | User user = new User(); |
17 | user.setFacebookUserId("FacebookUserId"); | 17 | user.setFacebookUserId("FacebookUserId"); |
18 | user.setTelegramUserId("TelegramUserId"); | 18 | user.setTelegramUserId("TelegramUserId"); |
19 | - user.setVegetarian(true); | ||
20 | 19 | ||
21 | entityManager.persist(user); | 20 | entityManager.persist(user); |
22 | } | 21 | } |