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,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 }