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