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,6 +8,8 @@ import de.bht.beuthbot.model.entities.GenericEntityAttribute; | ||
8 | import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | 8 | import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; |
9 | 9 | ||
10 | import java.io.IOException; | 10 | import java.io.IOException; |
11 | +import java.io.StringWriter; | ||
12 | +import java.io.Writer; | ||
11 | import java.util.List; | 13 | import java.util.List; |
12 | import java.util.stream.Collectors; | 14 | import java.util.stream.Collectors; |
13 | 15 | ||
@@ -29,9 +31,9 @@ public class GenericEntityAccessFacade { | @@ -29,9 +31,9 @@ public class GenericEntityAccessFacade { | ||
29 | String propertyAsJson; | 31 | String propertyAsJson; |
30 | 32 | ||
31 | if (isPrimitiveOrWrapperAttributeType(attributeType)) { | 33 | if (isPrimitiveOrWrapperAttributeType(attributeType)) { |
32 | - propertyAsJson = GenericEntityJsonConverter.toJson(property.getFirstValueOrNull()); | 34 | + propertyAsJson = writeGenericHierarchyToJson(property.getFirstValueOrNull()); |
33 | } else { | 35 | } else { |
34 | - propertyAsJson = GenericEntityJsonConverter.toJson(property); | 36 | + propertyAsJson = writeGenericHierarchyToJson(property); |
35 | } | 37 | } |
36 | 38 | ||
37 | return (T) JsonHelper.fromJson(propertyAsJson, attributeType); | 39 | return (T) JsonHelper.fromJson(propertyAsJson, attributeType); |
@@ -90,4 +92,17 @@ public class GenericEntityAccessFacade { | @@ -90,4 +92,17 @@ public class GenericEntityAccessFacade { | ||
90 | 92 | ||
91 | return mapper.readValue(json, type); | 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,6 +18,7 @@ import java.util.List; | ||
18 | /** | 18 | /** |
19 | * Created by Benjamin Rühl on 22.12.2017. | 19 | * Created by Benjamin Rühl on 22.12.2017. |
20 | * Helper class to serialize GenericEntity as if its generic attributes were normal fields | 20 | * Helper class to serialize GenericEntity as if its generic attributes were normal fields |
21 | + * @deprecated replaced by generic entity serializers | ||
21 | */ | 22 | */ |
22 | public class GenericEntityJsonConverter { | 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,6 +18,7 @@ import java.util.Map; | ||
18 | /** | 18 | /** |
19 | * Created by Benjamin Rühl on 03.12.2017. | 19 | * Created by Benjamin Rühl on 03.12.2017. |
20 | * Custom Hibernate UserType for mapping json typed columns in postgres to java maps | 20 | * Custom Hibernate UserType for mapping json typed columns in postgres to java maps |
21 | + * @deprecated Currently not in use | ||
21 | * @see <a href="http://vojtechruzicka.com/postgresqls-jsonb-type-mapping-using-hibernate/">vojtechruzicka.com</a> | 22 | * @see <a href="http://vojtechruzicka.com/postgresqls-jsonb-type-mapping-using-hibernate/">vojtechruzicka.com</a> |
22 | */ | 23 | */ |
23 | public class JsonMapUserType implements UserType { | 24 | public class JsonMapUserType implements UserType { |