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