diff --git a/src/main/java/de/thm/arsnova/entities/Answer.java b/src/main/java/de/thm/arsnova/entities/Answer.java index f3a251d33d81ac9ac33e6f10b6abfd30f4b479ec..c81adc7e8dcad3e12919f86249453215f07c3ed0 100644 --- a/src/main/java/de/thm/arsnova/entities/Answer.java +++ b/src/main/java/de/thm/arsnova/entities/Answer.java @@ -2,6 +2,8 @@ package de.thm.arsnova.entities; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonView; +import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver; +import de.thm.arsnova.entities.serialization.FormatAnswerTypeIdResolver; import de.thm.arsnova.entities.serialization.View; import org.springframework.core.style.ToStringCreator; @@ -9,14 +11,17 @@ import java.util.Map; import java.util.Objects; @JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.EXISTING_PROPERTY, - property = "type" + use = JsonTypeInfo.Id.CUSTOM, + property = "format", + visible = true, + defaultImpl = Answer.class ) -public abstract class Answer extends Entity { +@JsonTypeIdResolver(FormatAnswerTypeIdResolver.class) +public class Answer extends Entity { private String contentId; private String roomId; private String creatorId; + private Content.Format format; private int round; private Map<String, Map<String, ?>> extensions; @@ -49,6 +54,16 @@ public abstract class Answer extends Entity { this.creatorId = creatorId; } + @JsonView({View.Persistence.class, View.Public.class}) + public Content.Format getFormat() { + return format; + } + + @JsonView({View.Persistence.class, View.Public.class}) + public void setFormat(final Content.Format format) { + this.format = format; + } + @JsonView({View.Persistence.class, View.Public.class}) public int getRound() { return round; @@ -69,6 +84,12 @@ public abstract class Answer extends Entity { this.extensions = extensions; } + @JsonView(View.Persistence.class) + @Override + public Class<? extends Entity> getType() { + return Answer.class; + } + /** * {@inheritDoc} * @@ -97,6 +118,7 @@ public abstract class Answer extends Entity { .append("contentId", contentId) .append("roomId", roomId) .append("creatorId", creatorId) + .append("format", format) .append("round", round); } } diff --git a/src/main/java/de/thm/arsnova/entities/Content.java b/src/main/java/de/thm/arsnova/entities/Content.java index 45ad0e5734ca7ca9ffdf8ab22d5b405c1b7de8c9..11bf0c4f60cb2f5114e4f7d475c64e1c39fe4b8c 100644 --- a/src/main/java/de/thm/arsnova/entities/Content.java +++ b/src/main/java/de/thm/arsnova/entities/Content.java @@ -2,6 +2,8 @@ package de.thm.arsnova.entities; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonView; +import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver; +import de.thm.arsnova.entities.serialization.FormatContentTypeIdResolver; import de.thm.arsnova.entities.serialization.View; import org.springframework.core.style.ToStringCreator; @@ -12,10 +14,12 @@ import java.util.Objects; import java.util.Set; @JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.EXISTING_PROPERTY, - property = "type" + use = JsonTypeInfo.Id.CUSTOM, + property = "format", + visible = true, + defaultImpl = Content.class ) +@JsonTypeIdResolver(FormatContentTypeIdResolver.class) public class Content extends Entity { public enum Format { CHOICE, @@ -227,6 +231,12 @@ public class Content extends Entity { this.abstentionsAllowed = abstentionsAllowed; } + @JsonView(View.Persistence.class) + @Override + public Class<? extends Entity> getType() { + return Content.class; + } + /** * {@inheritDoc} * diff --git a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbDocumentModule.java b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbDocumentModule.java index a99adbf9711bf6b297ad3f5350e454a4624e54ea..bf6cfd26ce418719134b4c423d34094cbbb27b91 100644 --- a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbDocumentModule.java +++ b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbDocumentModule.java @@ -17,14 +17,8 @@ */ package de.thm.arsnova.entities.serialization; -import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.module.SimpleModule; -import de.thm.arsnova.entities.Answer; -import de.thm.arsnova.entities.ChoiceAnswer; -import de.thm.arsnova.entities.ChoiceQuestionContent; -import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Entity; -import de.thm.arsnova.entities.TextAnswer; public class CouchDbDocumentModule extends SimpleModule { public CouchDbDocumentModule() { @@ -35,11 +29,5 @@ public class CouchDbDocumentModule extends SimpleModule { public void setupModule(SetupContext context) { context.setMixInAnnotations(Entity.class, CouchDbDocumentMixIn.class); context.setMixInAnnotations(de.thm.arsnova.entities.migration.v2.Entity.class, CouchDbDocumentV2MixIn.class); - context.registerSubtypes( - new NamedType(Content.class, Content.class.getSimpleName()), - new NamedType(ChoiceQuestionContent.class, ChoiceQuestionContent.class.getSimpleName()), - new NamedType(Answer.class, Answer.class.getSimpleName()), - new NamedType(ChoiceAnswer.class, ChoiceAnswer.class.getSimpleName()), - new NamedType(TextAnswer.class, TextAnswer.class.getSimpleName())); } } diff --git a/src/main/java/de/thm/arsnova/entities/serialization/FormatAnswerTypeIdResolver.java b/src/main/java/de/thm/arsnova/entities/serialization/FormatAnswerTypeIdResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..5e2f3335bdbb9e908cb66f31119665d0c118e67e --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/serialization/FormatAnswerTypeIdResolver.java @@ -0,0 +1,53 @@ +package de.thm.arsnova.entities.serialization; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.DatabindContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase; +import com.fasterxml.jackson.databind.type.TypeFactory; +import de.thm.arsnova.entities.Answer; +import de.thm.arsnova.entities.ChoiceAnswer; +import de.thm.arsnova.entities.Content; +import de.thm.arsnova.entities.TextAnswer; + +import java.io.IOException; + +public class FormatAnswerTypeIdResolver extends TypeIdResolverBase { + @Override + public String idFromValue(final Object value) { + if (value instanceof Answer) { + return ((Answer) value).getFormat().toString(); + } else { + throw new IllegalArgumentException("Unsupported type."); + } + } + + @Override + public String idFromValueAndType(final Object value, final Class<?> suggestedType) { + return idFromValue(value); + } + + @Override + public JavaType typeFromId(final DatabindContext context, final String id) throws IOException { + Content.Format format = Content.Format.valueOf(id); + switch (format) { + case BINARY: + return TypeFactory.defaultInstance().constructType(ChoiceAnswer.class); + case CHOICE: + return TypeFactory.defaultInstance().constructType(ChoiceAnswer.class); + case NUMBER: + return TypeFactory.defaultInstance().constructType(ChoiceAnswer.class); + case SCALE: + return TypeFactory.defaultInstance().constructType(ChoiceAnswer.class); + case TEXT: + return TypeFactory.defaultInstance().constructType(TextAnswer.class); + default: + throw new IllegalArgumentException("Unsupported type ID."); + } + } + + @Override + public JsonTypeInfo.Id getMechanism() { + return JsonTypeInfo.Id.CUSTOM; + } +} diff --git a/src/main/java/de/thm/arsnova/entities/serialization/FormatContentTypeIdResolver.java b/src/main/java/de/thm/arsnova/entities/serialization/FormatContentTypeIdResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..2b28344601f25799e42d92a105ff2b031b51b763 --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/serialization/FormatContentTypeIdResolver.java @@ -0,0 +1,51 @@ +package de.thm.arsnova.entities.serialization; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.DatabindContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase; +import com.fasterxml.jackson.databind.type.TypeFactory; +import de.thm.arsnova.entities.ChoiceQuestionContent; +import de.thm.arsnova.entities.Content; + +import java.io.IOException; + +public class FormatContentTypeIdResolver extends TypeIdResolverBase { + @Override + public String idFromValue(final Object value) { + if (value instanceof Content) { + return ((Content) value).getFormat().toString(); + } else { + throw new IllegalArgumentException("Unsupported type."); + } + } + + @Override + public String idFromValueAndType(final Object value, final Class<?> suggestedType) { + return idFromValue(value); + } + + @Override + public JavaType typeFromId(final DatabindContext context, final String id) throws IOException { + Content.Format format = Content.Format.valueOf(id); + switch (format) { + case BINARY: + return TypeFactory.defaultInstance().constructType(ChoiceQuestionContent.class); + case CHOICE: + return TypeFactory.defaultInstance().constructType(ChoiceQuestionContent.class); + case NUMBER: + return TypeFactory.defaultInstance().constructType(ChoiceQuestionContent.class); + case SCALE: + return TypeFactory.defaultInstance().constructType(ChoiceQuestionContent.class); + case TEXT: + return TypeFactory.defaultInstance().constructType(Content.class); + default: + throw new IllegalArgumentException("Unsupported type ID."); + } + } + + @Override + public JsonTypeInfo.Id getMechanism() { + return JsonTypeInfo.Id.CUSTOM; + } +} diff --git a/src/main/resources/couchdb/Answer.design.js b/src/main/resources/couchdb/Answer.design.js index 88115413ec1eaf89067c473372781dfc3c329616..3e89d47b19c6d1875d7b4d134198f78259ad42c4 100644 --- a/src/main/resources/couchdb/Answer.design.js +++ b/src/main/resources/couchdb/Answer.design.js @@ -4,7 +4,7 @@ var designDoc = { "views": { "by_id": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit(doc._id, {_rev: doc._rev}); } }, @@ -12,14 +12,14 @@ var designDoc = { }, "by_contentid": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit(doc.contentId, {_rev: doc._rev}); } } }, "by_contentid_round_body_subject": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.contentId, doc.round, doc.abstention, doc.body, doc.subject, doc.successfulFreeTextAnswer], {_rev: doc._rev}); } }, @@ -27,7 +27,7 @@ var designDoc = { }, "by_contentid_round_selectedchoiceindexes": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.contentId, doc.round, doc.selectedChoiceIndexes], {_rev: doc._rev}); } }, @@ -35,21 +35,21 @@ var designDoc = { }, "by_contentid_creationtimestamp": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.contentId, doc.creationTimestamp], {_rev: doc._rev}); } } }, "by_contentid_creatorid_round": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.contentId, doc.creatorId, doc.round], {_rev: doc._rev}); } } }, "by_roomid": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit(doc.roomId, {_rev: doc._rev}); } }, @@ -57,7 +57,7 @@ var designDoc = { }, "by_roomid_variant": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.roomId, doc.questionVariant], {_rev: doc._rev}); } }, @@ -65,21 +65,21 @@ var designDoc = { }, "by_creatorid_roomid": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.creatorId, doc.roomId], {_rev: doc._rev}); } } }, "contentid_by_creatorid_roomid_variant": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.user, doc.roomId, doc.questionVariant], doc.contentId); } } }, "contentid_round_by_creatorid_roomid_variant": { "map": function (doc) { - if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) { + if (doc.type === "Answer") { emit([doc.creatorId, doc.roomId, doc.questionVariant], [doc.contentId, doc.round]); } } diff --git a/src/main/resources/couchdb/Content.design.js b/src/main/resources/couchdb/Content.design.js index 9c130da96c2b1515303fd897d2ec4d82c241f25a..5b09c23f6fe15cb03a481f2c737ee23d54f8a0d3 100644 --- a/src/main/resources/couchdb/Content.design.js +++ b/src/main/resources/couchdb/Content.design.js @@ -4,7 +4,7 @@ var designDoc = { "views": { "by_id": { "map": function (doc) { - if (["Content", "ChoiceQuestionContent"].indexOf(doc.type) !== -1) { + if (doc.type === "Content") { emit(doc._id, {_rev: doc._rev}); } }, @@ -12,7 +12,7 @@ var designDoc = { }, "by_roomid": { "map": function (doc) { - if (["Content", "ChoiceQuestionContent"].indexOf(doc.type) !== -1) { + if (doc.type === "Content") { emit(doc.roomId, {_rev: doc._rev}); } }, @@ -20,7 +20,7 @@ var designDoc = { }, "by_roomid_group_locked": { "map": function (doc) { - if (["Content", "ChoiceQuestionContent"].indexOf(doc.type) !== -1) { + if (doc.type === "Content") { emit([doc.roomId, doc.group, doc.locked, doc.subject, doc.body.substr(0, 16)], {_rev: doc._rev}); } },