Commit 302c0d25f2c9ce1e796272d54bf277332096dc66
1 parent
2c012f58
Rework generic entity serialization using custom json serializers instead of json converter
Showing
6 changed files
with
199 additions
and
2 deletions
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityAccessFacade.java
| ... | ... | @@ -8,6 +8,8 @@ import de.bht.beuthbot.model.entities.GenericEntityAttribute; |
| 8 | 8 | import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; |
| 9 | 9 | |
| 10 | 10 | import java.io.IOException; |
| 11 | +import java.io.StringWriter; | |
| 12 | +import java.io.Writer; | |
| 11 | 13 | import java.util.List; |
| 12 | 14 | import java.util.stream.Collectors; |
| 13 | 15 | |
| ... | ... | @@ -29,9 +31,9 @@ public class GenericEntityAccessFacade { |
| 29 | 31 | String propertyAsJson; |
| 30 | 32 | |
| 31 | 33 | if (isPrimitiveOrWrapperAttributeType(attributeType)) { |
| 32 | - propertyAsJson = GenericEntityJsonConverter.toJson(property.getFirstValueOrNull()); | |
| 34 | + propertyAsJson = writeGenericHierarchyToJson(property.getFirstValueOrNull()); | |
| 33 | 35 | } else { |
| 34 | - propertyAsJson = GenericEntityJsonConverter.toJson(property); | |
| 36 | + propertyAsJson = writeGenericHierarchyToJson(property); | |
| 35 | 37 | } |
| 36 | 38 | |
| 37 | 39 | return (T) JsonHelper.fromJson(propertyAsJson, attributeType); |
| ... | ... | @@ -90,4 +92,17 @@ public class GenericEntityAccessFacade { |
| 90 | 92 | |
| 91 | 93 | return mapper.readValue(json, type); |
| 92 | 94 | } |
| 95 | + | |
| 96 | + private static String writeGenericHierarchyToJson(Object value) throws IOException { | |
| 97 | + ObjectMapper mapper = new ObjectMapper(); | |
| 98 | + SimpleModule module = new SimpleModule(); | |
| 99 | + module.addSerializer(GenericEntity.class, new GenericEntitySerializer()); | |
| 100 | + module.addSerializer(GenericEntityAttribute.class, new GenericEntityAttributeSerializer()); | |
| 101 | + module.addSerializer(GenericEntityAttributeValue.class, new GenericEntityAttributeValueSerializer()); | |
| 102 | + mapper.registerModule(module); | |
| 103 | + | |
| 104 | + Writer stringWriter = new StringWriter(); | |
| 105 | + mapper.writeValue(stringWriter, value); | |
| 106 | + return stringWriter.toString(); | |
| 107 | + } | |
| 93 | 108 | } | ... | ... |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityAttributeSerializer.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.core.JsonGenerationException; | |
| 4 | +import com.fasterxml.jackson.core.JsonGenerator; | |
| 5 | +import com.fasterxml.jackson.databind.SerializerProvider; | |
| 6 | +import com.fasterxml.jackson.databind.ser.std.StdSerializer; | |
| 7 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | |
| 8 | +import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | |
| 9 | + | |
| 10 | +import java.io.IOException; | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Created by Benjamin Rühl on 14.01.2018. | |
| 15 | + */ | |
| 16 | +public class GenericEntityAttributeSerializer extends StdSerializer<GenericEntityAttribute> { | |
| 17 | + | |
| 18 | + private GenericEntityAttributeValueSerializer attributeValueSerializer = new GenericEntityAttributeValueSerializer(); | |
| 19 | + | |
| 20 | + public GenericEntityAttributeSerializer() { | |
| 21 | + this(GenericEntityAttribute.class); | |
| 22 | + } | |
| 23 | + | |
| 24 | + public GenericEntityAttributeSerializer(Class<GenericEntityAttribute> t) { | |
| 25 | + super(t); | |
| 26 | + } | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public void serialize(GenericEntityAttribute value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { | |
| 30 | + List<GenericEntityAttributeValue> attributeValues = value.getValues(); | |
| 31 | + | |
| 32 | + jgen.writeStartObject(); | |
| 33 | + jgen.writeFieldName(value.getName()); | |
| 34 | + | |
| 35 | + if (attributeValues == null || attributeValues.isEmpty()) { | |
| 36 | + jgen.writeNullField(value.getName()); | |
| 37 | + } else if (attributeValues.size() == 1) { | |
| 38 | + attributeValueSerializer.serialize(value.getValues().get(0), jgen, provider); | |
| 39 | + } else { | |
| 40 | + jgen.writeArrayFieldStart(value.getName()); | |
| 41 | + | |
| 42 | + for (GenericEntityAttributeValue genericValue : value.getValues()) { | |
| 43 | + attributeValueSerializer.serialize(genericValue, jgen, provider); | |
| 44 | + } | |
| 45 | + | |
| 46 | + jgen.writeEndArray(); | |
| 47 | + } | |
| 48 | + | |
| 49 | + jgen.writeEndObject(); | |
| 50 | + } | |
| 51 | +} | ... | ... |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityAttributeValueSerializer.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.core.JsonGenerationException; | |
| 4 | +import com.fasterxml.jackson.core.JsonGenerator; | |
| 5 | +import com.fasterxml.jackson.databind.SerializerProvider; | |
| 6 | +import com.fasterxml.jackson.databind.ser.std.StdSerializer; | |
| 7 | +import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | |
| 8 | + | |
| 9 | +import java.io.IOException; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Created by Benjamin Rühl on 14.01.2018. | |
| 13 | + */ | |
| 14 | +public class GenericEntityAttributeValueSerializer extends StdSerializer<GenericEntityAttributeValue> { | |
| 15 | + | |
| 16 | + public GenericEntityAttributeValueSerializer() { | |
| 17 | + this(GenericEntityAttributeValue.class); | |
| 18 | + } | |
| 19 | + | |
| 20 | + public GenericEntityAttributeValueSerializer(Class<GenericEntityAttributeValue> t) { | |
| 21 | + super(t); | |
| 22 | + } | |
| 23 | + | |
| 24 | + @Override | |
| 25 | + public void serialize(GenericEntityAttributeValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { | |
| 26 | + if (value.getValueAsBool() != null) { | |
| 27 | + jgen.writeBoolean(value.getValueAsBool()); | |
| 28 | + } else if (value.getValueAsLong() != null) { | |
| 29 | + jgen.writeNumber(value.getValueAsLong()); | |
| 30 | + } else if (value.getValueAsDouble() != null) { | |
| 31 | + jgen.writeNumber(value.getValueAsDouble()); | |
| 32 | + } else if (value.getValueAsString() != null) { | |
| 33 | + jgen.writeString(value.getValueAsString()); | |
| 34 | + } else if (value.getValueAsEntity() != null) { | |
| 35 | + new GenericEntitySerializer().serialize(value.getValueAsEntity(), jgen, provider); | |
| 36 | + } | |
| 37 | + } | |
| 38 | +} | ... | ... |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityJsonConverter.java
| ... | ... | @@ -18,6 +18,7 @@ import java.util.List; |
| 18 | 18 | /** |
| 19 | 19 | * Created by Benjamin Rühl on 22.12.2017. |
| 20 | 20 | * Helper class to serialize GenericEntity as if its generic attributes were normal fields |
| 21 | + * @deprecated replaced by generic entity serializers | |
| 21 | 22 | */ |
| 22 | 23 | public class GenericEntityJsonConverter { |
| 23 | 24 | ... | ... |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntitySerializer.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.core.JsonGenerationException; | |
| 4 | +import com.fasterxml.jackson.core.JsonGenerator; | |
| 5 | +import com.fasterxml.jackson.databind.SerializerProvider; | |
| 6 | +import com.fasterxml.jackson.databind.ser.std.StdSerializer; | |
| 7 | +import de.bht.beuthbot.model.entities.GenericEntity; | |
| 8 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | |
| 9 | +import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | |
| 10 | + | |
| 11 | +import java.io.IOException; | |
| 12 | +import java.lang.reflect.Field; | |
| 13 | +import java.lang.reflect.ParameterizedType; | |
| 14 | +import java.lang.reflect.Type; | |
| 15 | +import java.util.Arrays; | |
| 16 | +import java.util.List; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * Created by Benjamin Rühl on 14.01.2018. | |
| 20 | + */ | |
| 21 | +public class GenericEntitySerializer extends StdSerializer<GenericEntity> { | |
| 22 | + | |
| 23 | + private GenericEntityAttributeSerializer attributeSerializer = new GenericEntityAttributeSerializer(); | |
| 24 | + | |
| 25 | + public GenericEntitySerializer() { | |
| 26 | + this(GenericEntity.class); | |
| 27 | + } | |
| 28 | + | |
| 29 | + public GenericEntitySerializer(Class<GenericEntity> t) { | |
| 30 | + super(t); | |
| 31 | + } | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * Uses a JsonGenerator to append a GenericEntity and its content to json. | |
| 35 | + * Does not open the json object because this part depends on whether the object stands for itself or is the value of a field. | |
| 36 | + * However it does close the object. | |
| 37 | + * @throws IOException | |
| 38 | + */ | |
| 39 | + @Override | |
| 40 | + public void serialize(GenericEntity value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { | |
| 41 | + jgen.writeStartObject(); | |
| 42 | + | |
| 43 | + writeClassFieldsWithoutGenericEntityHierarchy(jgen, value); | |
| 44 | + | |
| 45 | + for (GenericEntityAttribute genericAttribute : value.getAttributes()) { | |
| 46 | + attributeSerializer.serialize(genericAttribute, jgen, provider); | |
| 47 | + } | |
| 48 | + | |
| 49 | + jgen.writeEndObject(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Uses a JsonGenerator to append all fields and their values of the targetObject to json. | |
| 54 | + * Ignores fields that have GenericEntity, GenericEntityAttribute or GenericEntityAttributeValue as type or generic list parameter. | |
| 55 | + * @throws IOException | |
| 56 | + */ | |
| 57 | + private void writeClassFieldsWithoutGenericEntityHierarchy(JsonGenerator jsonGenerator, Object targetObject) throws IOException { | |
| 58 | + for (Field field : targetObject.getClass().getFields()) { | |
| 59 | + if (isGenericEntityHierarchyType(field)) | |
| 60 | + continue; | |
| 61 | + | |
| 62 | + try { | |
| 63 | + jsonGenerator.writeObjectField(field.getName(), field.get(targetObject)); | |
| 64 | + } catch (Exception e) { | |
| 65 | + jsonGenerator.writeStringField(field.getName(), e.getClass().getName()); | |
| 66 | + e.printStackTrace(); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * Determines whether the field's type is GenericEntity, GenericEntityAttribute or GenericEntityAttributeValue | |
| 73 | + * or a list type with one of those types as generic type parameter. | |
| 74 | + */ | |
| 75 | + private boolean isGenericEntityHierarchyType(Field field) { | |
| 76 | + List<Class> typesOfGenericEntityHierarchy = Arrays.asList(GenericEntity.class, GenericEntityAttribute.class, GenericEntityAttributeValue.class); | |
| 77 | + | |
| 78 | + // check for list types | |
| 79 | + try { | |
| 80 | + if (Iterable.class.isAssignableFrom(field.getType())) { | |
| 81 | + Type fieldFirstGenericType = ((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]; | |
| 82 | + if (typesOfGenericEntityHierarchy.contains(fieldFirstGenericType.getClass())) | |
| 83 | + return true; | |
| 84 | + } | |
| 85 | + } catch (Exception e) { | |
| 86 | + // not a list or not generic | |
| 87 | + } | |
| 88 | + | |
| 89 | + return typesOfGenericEntityHierarchy.contains(field.getType()); | |
| 90 | + } | |
| 91 | +} | ... | ... |
services/Common/src/main/java/de/bht/beuthbot/persistence/JsonMapUserType.java
| ... | ... | @@ -18,6 +18,7 @@ import java.util.Map; |
| 18 | 18 | /** |
| 19 | 19 | * Created by Benjamin Rühl on 03.12.2017. |
| 20 | 20 | * Custom Hibernate UserType for mapping json typed columns in postgres to java maps |
| 21 | + * @deprecated Currently not in use | |
| 21 | 22 | * @see <a href="http://vojtechruzicka.com/postgresqls-jsonb-type-mapping-using-hibernate/">vojtechruzicka.com</a> |
| 22 | 23 | */ |
| 23 | 24 | public class JsonMapUserType implements UserType { | ... | ... |