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 | 7 | |
8 | 8 | String getFacebookUserId(); |
9 | 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 | 15 | "org.hibernate:hibernate-core:5.2.12.Final", |
16 | 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 | 20 | providedCompile "org.slf4j:slf4j-api:1.7.25" |
20 | 21 | ... | ... |
services/Global/src/main/java/de/bht/beuthbot/entities/EntityBase.java
1 | 1 | package de.bht.beuthbot.entities; |
2 | 2 | |
3 | 3 | import de.bht.beuthbot.model.entities.Entity; |
4 | +import de.bht.beuthbot.persistence.JsonMapUserType; | |
5 | +import org.hibernate.annotations.TypeDef; | |
4 | 6 | |
5 | 7 | import javax.persistence.*; |
6 | 8 | import java.util.Date; |
... | ... | @@ -10,6 +12,8 @@ import java.util.Objects; |
10 | 12 | * Created by Benjamin Rühl on 19.11.2017. |
11 | 13 | */ |
12 | 14 | @MappedSuperclass |
15 | +@Access(AccessType.FIELD) | |
16 | +@TypeDef(name = "JsonMapType", typeClass = JsonMapUserType.class) | |
13 | 17 | public class EntityBase implements Entity { |
14 | 18 | |
15 | 19 | @Id |
... | ... | @@ -63,7 +67,7 @@ public class EntityBase implements Entity { |
63 | 67 | if (other.getId() == 0 && getId() == 0) |
64 | 68 | return super.equals(obj); |
65 | 69 | |
66 | - return other.getId() == getId(); | |
70 | + return Objects.equals(other.getId(), getId()); | |
67 | 71 | } |
68 | 72 | |
69 | 73 | @Override | ... | ... |
services/Global/src/main/java/de/bht/beuthbot/entities/User.java
1 | 1 | package de.bht.beuthbot.entities; |
2 | 2 | |
3 | +import de.bht.beuthbot.persistence.JsonHelper; | |
4 | +import org.hibernate.annotations.Type; | |
5 | + | |
3 | 6 | import javax.persistence.Entity; |
4 | 7 | import javax.persistence.Table; |
8 | +import java.util.HashMap; | |
9 | +import java.util.Map; | |
5 | 10 | |
6 | 11 | /** |
7 | 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 | 17 | |
13 | 18 | private String facebookUserId; |
14 | 19 | private String telegramUserId; |
15 | - private boolean isVegetarian; | |
20 | + | |
21 | + @Type(type = "JsonMapType") | |
22 | + private Map<String, String> additionalData = new HashMap<>(); | |
16 | 23 | |
17 | 24 | @Override |
18 | 25 | public String getFacebookUserId() { |
... | ... | @@ -25,8 +32,19 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U |
25 | 32 | } |
26 | 33 | |
27 | 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 | 50 | public void setFacebookUserId(String facebookUserId) { |
... | ... | @@ -36,8 +54,4 @@ public class User extends EntityBase implements de.bht.beuthbot.model.entities.U |
36 | 54 | public void setTelegramUserId(String telegramUserId) { |
37 | 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