Commit 302c0d25f2c9ce1e796272d54bf277332096dc66

Authored by Benjamin Rühl
1 parent 2c012f58

Rework generic entity serialization using custom json serializers instead of json converter

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 {
... ...