Commit 257a3b7900bcb1ab50b2c99ad8e8edca31679b6f

Authored by benruehl
1 parent 201450f1

Add json properties with hibernate UserType mapping to 'user' entity

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
... ... @@ -16,7 +16,6 @@ public class UserManager {
16 16 User user = new User();
17 17 user.setFacebookUserId("FacebookUserId");
18 18 user.setTelegramUserId("TelegramUserId");
19   - user.setVegetarian(true);
20 19  
21 20 entityManager.persist(user);
22 21 }
... ...