From bf98307d9d32d8a18fc1fb0c051721f942ca7e0e Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Wed, 15 Mar 2023 10:03:08 +0100 Subject: [PATCH 1/6] adds serializations tests for exportform Signed-off-by: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> --- .../bakdata/conquery/apiv1/forms/Form.java | 3 + .../apiv1/forms/export_form/AbsoluteMode.java | 3 + .../forms/export_form/EntityDateMode.java | 2 + .../apiv1/forms/export_form/ExportForm.java | 6 + .../apiv1/forms/export_form/Mode.java | 3 + .../apiv1/forms/export_form/RelativeMode.java | 5 +- .../conquery/apiv1/query/CQElement.java | 2 + .../apiv1/query/concept/filter/CQTable.java | 3 + .../query/concept/filter/FilterValue.java | 2 + .../query/concept/specific/CQConcept.java | 2 + .../conquery/models/auth/entities/User.java | 2 +- .../models/datasets/concepts/Concept.java | 2 + .../datasets/concepts/ConceptElement.java | 6 +- .../models/datasets/concepts/Connector.java | 3 + .../datasets/concepts/filters/Filter.java | 2 + .../datasets/concepts/select/Select.java | 2 + .../models/execution/ManagedExecution.java | 12 ++ .../models/forms/managed/ManagedForm.java | 18 +-- .../forms/managed/ManagedInternalForm.java | 12 +- .../ids/specific/ManagedExecutionId.java | 2 +- .../conquery/api/form/config/TestForm.java | 14 +- .../serializer/SerializationTestUtil.java | 9 +- .../conquery/models/SerializationTests.java | 102 +++++++------- .../types/SerialisationObjectsUtil.java | 130 ++++++++++++++++++ 24 files changed, 264 insertions(+), 83 deletions(-) create mode 100644 backend/src/test/java/com/bakdata/conquery/models/types/SerialisationObjectsUtil.java diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/Form.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/Form.java index 783015148c..451c39d333 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/Form.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/Form.java @@ -14,6 +14,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ClassToInstanceMap; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.Setter; @@ -21,6 +22,7 @@ /** * API representation of a form query. */ +@EqualsAndHashCode public abstract class Form implements QueryDescription { /** @@ -30,6 +32,7 @@ public abstract class Form implements QueryDescription { @Nullable @Getter @Setter + @EqualsAndHashCode.Exclude private JsonNode values; @JsonIgnore diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/AbsoluteMode.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/AbsoluteMode.java index 1b7e00d556..c71dbd788c 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/AbsoluteMode.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/AbsoluteMode.java @@ -18,12 +18,14 @@ import com.bakdata.conquery.models.query.QueryResolveContext; import com.bakdata.conquery.models.query.Visitable; import com.fasterxml.jackson.annotation.JsonView; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @Getter @Setter @CPSType(id = "ABSOLUTE", base = Mode.class) +@EqualsAndHashCode(callSuper = true, doNotUseGetters = true) public class AbsoluteMode extends Mode { @NotNull @Valid @@ -35,6 +37,7 @@ public class AbsoluteMode extends Mode { @JsonView(View.InternalCommunication.class) + @EqualsAndHashCode.Exclude private ArrayConceptQuery resolvedFeatures; @Override diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/EntityDateMode.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/EntityDateMode.java index 619c5668db..a7223e4e69 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/EntityDateMode.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/EntityDateMode.java @@ -19,6 +19,7 @@ import com.bakdata.conquery.models.query.QueryResolveContext; import com.bakdata.conquery.models.query.Visitable; import com.fasterxml.jackson.annotation.JsonView; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -43,6 +44,7 @@ public void visit(Consumer visitor) { @JsonView(View.InternalCommunication.class) + @EqualsAndHashCode.Exclude private ArrayConceptQuery resolvedFeatures; @Override diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/ExportForm.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/ExportForm.java index 7021a7d74e..381e4bf70d 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/ExportForm.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/ExportForm.java @@ -39,6 +39,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; import lombok.AccessLevel; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -46,6 +47,7 @@ @Getter @Setter @CPSType(id = "EXPORT_FORM", base = QueryDescription.class) +@EqualsAndHashCode(callSuper = true) public class ExportForm extends Form implements InternalForm { @NotNull @@ -53,6 +55,7 @@ public class ExportForm extends Form implements InternalForm { private ManagedExecutionId queryGroupId; @JsonIgnore + @EqualsAndHashCode.Exclude private ManagedQuery queryGroup; @NotNull @@ -61,6 +64,7 @@ public class ExportForm extends Form implements InternalForm { private Mode timeMode; @NotEmpty + @Valid private List features = ImmutableList.of(); @NotNull @@ -70,8 +74,10 @@ public class ExportForm extends Form implements InternalForm { private boolean alsoCreateCoarserSubdivisions = false; @JsonIgnore + @EqualsAndHashCode.Exclude private Query prerequisite; @JsonIgnore + @EqualsAndHashCode.Exclude private List resolvedResolutions; @Override public void visit(Consumer visitor) { diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/Mode.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/Mode.java index c44b6d525a..56243c6db2 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/Mode.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/Mode.java @@ -6,16 +6,19 @@ import com.bakdata.conquery.models.query.Visitable; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.PROPERTY, property = "value") @CPSBase +@EqualsAndHashCode public abstract class Mode implements Visitable { @Getter @Setter @JsonBackReference + @EqualsAndHashCode.Exclude private ExportForm form; public abstract void resolve(QueryResolveContext context); diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/RelativeMode.java b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/RelativeMode.java index 9c4d0f24e6..07c5007341 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/RelativeMode.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/forms/export_form/RelativeMode.java @@ -17,11 +17,13 @@ import com.bakdata.conquery.models.query.QueryResolveContext; import com.bakdata.conquery.models.query.Visitable; import com.fasterxml.jackson.annotation.JsonView; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @Getter @Setter -@CPSType(id="RELATIVE", base=Mode.class) +@CPSType(id = "RELATIVE", base = Mode.class) +@EqualsAndHashCode(callSuper = true) public class RelativeMode extends Mode { @NotNull private CalendarUnit timeUnit; @@ -36,6 +38,7 @@ public class RelativeMode extends Mode { @JsonView(View.InternalCommunication.class) + @EqualsAndHashCode.Exclude private ArrayConceptQuery resolvedFeatures; @Override diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/query/CQElement.java b/backend/src/main/java/com/bakdata/conquery/apiv1/query/CQElement.java index 6f4a9fe289..704e672cb8 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/query/CQElement.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/query/CQElement.java @@ -23,11 +23,13 @@ import com.bakdata.conquery.models.query.resultinfo.ResultInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type") @CPSBase +@EqualsAndHashCode public abstract class CQElement implements Visitable { /** diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/query/concept/filter/CQTable.java b/backend/src/main/java/com/bakdata/conquery/apiv1/query/concept/filter/CQTable.java index 52a17dd036..bea2268426 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/query/concept/filter/CQTable.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/query/concept/filter/CQTable.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.dropwizard.validation.ValidationMethod; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -25,6 +26,7 @@ @Getter @Setter @ToString(exclude = "concept") +@EqualsAndHashCode public class CQTable { @Valid @NotNull @@ -35,6 +37,7 @@ public class CQTable { private List, NamespacedIdentifiable { public static final int[] NOT_CONTAINED = new int[]{-1}; @@ -52,6 +54,7 @@ public abstract class Connector extends Labeled implements SelectHo private List validityDates = new ArrayList<>(); @JsonBackReference + @EqualsAndHashCode.Exclude private Concept concept; @JsonIgnore diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java index 98097bc40c..243d90f8e1 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.dropwizard.validation.ValidationMethod; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -31,6 +32,7 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type") @CPSBase @Slf4j +@EqualsAndHashCode(callSuper = true) public abstract class Filter extends Labeled implements NamespacedIdentifiable { private String unit; diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java index b66174f619..8164e12a25 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.dropwizard.validation.ValidationMethod; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -30,6 +31,7 @@ @JsonTypeInfo(use=JsonTypeInfo.Id.CUSTOM, property="type") @CPSBase @Slf4j +@EqualsAndHashCode(callSuper = true) public abstract class Select extends Labeled implements NamespacedIdentifiable { @JsonBackReference @Getter @Setter diff --git a/backend/src/main/java/com/bakdata/conquery/models/execution/ManagedExecution.java b/backend/src/main/java/com/bakdata/conquery/models/execution/ManagedExecution.java index 305fc7c18b..047ecc25eb 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/execution/ManagedExecution.java +++ b/backend/src/main/java/com/bakdata/conquery/models/execution/ManagedExecution.java @@ -52,6 +52,7 @@ import com.google.common.base.Preconditions; import com.google.common.util.concurrent.Uninterruptibles; import lombok.AccessLevel; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.Setter; @@ -66,6 +67,7 @@ @Slf4j @CPSBase @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type") +@EqualsAndHashCode(callSuper = false) public abstract class ManagedExecution extends IdentifiableImpl implements Taggable, Shareable, Labelable, Owned, Visitable { /** @@ -94,28 +96,38 @@ public abstract class ManagedExecution extends IdentifiableImpl extends ManagedExecution { +public abstract class ManagedForm extends ManagedExecution { - /** - * The form that was submitted through the api. - */ + @Getter private F submittedForm; protected ManagedForm(@JacksonInject(useInput = OptBoolean.FALSE) MetaStorage storage) { super(storage); } - public ManagedForm(F submittedForm, User owner, Dataset submittedDataset, MetaStorage storage) { + protected ManagedForm(F submittedForm, User owner, Dataset submittedDataset, MetaStorage storage) { super(owner, submittedDataset, storage); this.submittedForm = submittedForm; } - @Override - protected void doInitExecutable() { - - } @Override public void start() { @@ -79,7 +69,7 @@ public void visit(Consumer visitor) { @Override @JsonIgnore - public QueryDescription getSubmitted() { + public F getSubmitted() { return submittedForm; } diff --git a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedInternalForm.java b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedInternalForm.java index ce226b0292..67c15c0864 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedInternalForm.java +++ b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedInternalForm.java @@ -41,6 +41,7 @@ @Slf4j @CPSType(base = ManagedExecution.class, id = "INTERNAL_FORM") @Getter +@EqualsAndHashCode(callSuper = true) public class ManagedInternalForm extends ManagedForm implements SingleTableResult, InternalExecution { @@ -49,10 +50,11 @@ public class ManagedInternalForm extends ManagedF * This is required by forms that have multiple results (CSVs) as output. */ @JsonIgnore + @EqualsAndHashCode.Exclude private Map subQueries; /** - * Subqueries that are send to the workers. + * Subqueries that are sent to the workers. */ @JsonIgnore @EqualsAndHashCode.Exclude @@ -69,7 +71,7 @@ public ManagedInternalForm(F form, User user, Dataset submittedDataset, MetaStor @Override public void doInitExecutable() { // Convert sub queries to sub executions - getSubmittedForm().resolve(new QueryResolveContext(getNamespace(), getConfig(), getStorage(), null)); + getSubmitted().resolve(new QueryResolveContext(getNamespace(), getConfig(), getStorage(), null)); subQueries = createSubExecutions(); // Initialize sub executions @@ -78,9 +80,9 @@ public void doInitExecutable() { @NotNull private Map createSubExecutions() { - return getSubmittedForm().createSubQueries() - .entrySet() - .stream().collect(Collectors.toMap( + return getSubmitted().createSubQueries() + .entrySet() + .stream().collect(Collectors.toMap( e -> e.getKey(), e -> e.getValue().toManagedExecution(getOwner(), getDataset(), getStorage()) diff --git a/backend/src/main/java/com/bakdata/conquery/models/identifiable/ids/specific/ManagedExecutionId.java b/backend/src/main/java/com/bakdata/conquery/models/identifiable/ids/specific/ManagedExecutionId.java index 32671646eb..f0a2d62e40 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/identifiable/ids/specific/ManagedExecutionId.java +++ b/backend/src/main/java/com/bakdata/conquery/models/identifiable/ids/specific/ManagedExecutionId.java @@ -13,7 +13,7 @@ @AllArgsConstructor @Getter -@EqualsAndHashCode(callSuper = false) +@EqualsAndHashCode(callSuper = false, doNotUseGetters = true) public class ManagedExecutionId extends Id { private final DatasetId dataset; diff --git a/backend/src/test/java/com/bakdata/conquery/api/form/config/TestForm.java b/backend/src/test/java/com/bakdata/conquery/api/form/config/TestForm.java index a7eff2196f..97f7d36c88 100644 --- a/backend/src/test/java/com/bakdata/conquery/api/form/config/TestForm.java +++ b/backend/src/test/java/com/bakdata/conquery/api/form/config/TestForm.java @@ -1,26 +1,34 @@ package com.bakdata.conquery.api.form.config; import java.util.Collections; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; import com.bakdata.conquery.apiv1.forms.Form; +import com.bakdata.conquery.apiv1.forms.InternalForm; +import com.bakdata.conquery.apiv1.query.Query; import com.bakdata.conquery.apiv1.query.QueryDescription; import com.bakdata.conquery.io.cps.CPSType; import com.bakdata.conquery.io.storage.MetaStorage; import com.bakdata.conquery.models.auth.entities.User; import com.bakdata.conquery.models.datasets.Dataset; import com.bakdata.conquery.models.execution.ManagedExecution; -import com.bakdata.conquery.models.forms.managed.ManagedForm; +import com.bakdata.conquery.models.forms.managed.ManagedInternalForm; import com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId; import com.bakdata.conquery.models.query.QueryResolveContext; import com.bakdata.conquery.models.query.Visitable; -public abstract class TestForm extends Form { +public abstract class TestForm extends Form implements InternalForm { @Override public ManagedExecution toManagedExecution(User user, Dataset submittedDataset, MetaStorage storage) { - return new ManagedForm(this, user, submittedDataset, storage); + return new ManagedInternalForm<>(this, user, submittedDataset, storage); + } + + @Override + public Map createSubQueries() { + return Collections.emptyMap(); } @Override diff --git a/backend/src/test/java/com/bakdata/conquery/io/jackson/serializer/SerializationTestUtil.java b/backend/src/test/java/com/bakdata/conquery/io/jackson/serializer/SerializationTestUtil.java index 859a2d87f1..37d880f9f4 100644 --- a/backend/src/test/java/com/bakdata/conquery/io/jackson/serializer/SerializationTestUtil.java +++ b/backend/src/test/java/com/bakdata/conquery/io/jackson/serializer/SerializationTestUtil.java @@ -59,6 +59,8 @@ public class SerializationTestUtil { @NonNull private Injectable[] injectables = {}; + private boolean forceHashCodeEqual = false; + public static SerializationTestUtil forType(TypeReference type) { return new SerializationTestUtil<>(Jackson.MAPPER.getTypeFactory().constructType(type)); } @@ -77,6 +79,11 @@ public SerializationTestUtil injectables(Injectable... injectables) { return this; } + public SerializationTestUtil checkHashCode() { + this.forceHashCodeEqual = true; + return this; + } + public void test(T value, T expected) throws JSONException, IOException { if (objectMappers == null || objectMappers.length == 0) { fail("No objectmappers were set"); @@ -117,7 +124,7 @@ private void test(T value, T expected, ObjectMapper mapper) throws IOException { ValidatorHelper.failOnError(log, validator.validate(copy)); //because IdentifiableImp cashes the hash - if (value instanceof IdentifiableImpl) { + if (value instanceof IdentifiableImpl || forceHashCodeEqual) { assertThat(copy.hashCode()).isEqualTo(value.hashCode()); } diff --git a/backend/src/test/java/com/bakdata/conquery/models/SerializationTests.java b/backend/src/test/java/com/bakdata/conquery/models/SerializationTests.java index f6a6ed5acc..26fc8d2a26 100644 --- a/backend/src/test/java/com/bakdata/conquery/models/SerializationTests.java +++ b/backend/src/test/java/com/bakdata/conquery/models/SerializationTests.java @@ -1,5 +1,7 @@ package com.bakdata.conquery.models; +import static com.bakdata.conquery.models.types.SerialisationObjectsUtil.*; + import java.io.IOException; import java.time.LocalDate; import java.time.temporal.ChronoUnit; @@ -23,6 +25,7 @@ import com.bakdata.conquery.apiv1.forms.export_form.ExportForm; import com.bakdata.conquery.apiv1.query.ArrayConceptQuery; import com.bakdata.conquery.apiv1.query.ConceptQuery; +import com.bakdata.conquery.apiv1.query.QueryDescription; import com.bakdata.conquery.apiv1.query.concept.filter.CQTable; import com.bakdata.conquery.apiv1.query.concept.specific.CQConcept; import com.bakdata.conquery.apiv1.query.concept.specific.CQOr; @@ -46,7 +49,6 @@ import com.bakdata.conquery.models.datasets.Dataset; import com.bakdata.conquery.models.datasets.Import; import com.bakdata.conquery.models.datasets.Table; -import com.bakdata.conquery.models.datasets.concepts.ValidityDate; import com.bakdata.conquery.models.datasets.concepts.tree.ConceptTreeConnector; import com.bakdata.conquery.models.datasets.concepts.tree.TreeConcept; import com.bakdata.conquery.models.dictionary.Dictionary; @@ -65,6 +67,7 @@ import com.bakdata.conquery.models.forms.configs.FormConfig; import com.bakdata.conquery.models.forms.frontendconfiguration.FormConfigProcessor; import com.bakdata.conquery.models.forms.managed.AbsoluteFormQuery; +import com.bakdata.conquery.models.forms.managed.ManagedInternalForm; import com.bakdata.conquery.models.forms.util.Alignment; import com.bakdata.conquery.models.forms.util.Resolution; import com.bakdata.conquery.models.identifiable.CentralRegistry; @@ -282,60 +285,11 @@ public void table() throws JSONException, IOException { @Test public void treeConcept() throws IOException, JSONException { - Dataset dataset = new Dataset(); - dataset.setName("datasetName"); - - TreeConcept concept = new TreeConcept(); - concept.setDataset(dataset); - concept.setLabel("conceptLabel"); - concept.setName("conceptName"); - - Table table = new Table(); - - Column column = new Column(); - column.setLabel("colLabel"); - column.setName("colName"); - column.setType(MajorTypeId.STRING); - column.setTable(table); - - Column dateColumn = new Column(); - dateColumn.setLabel("colLabel2"); - dateColumn.setName("colName2"); - dateColumn.setType(MajorTypeId.DATE); - dateColumn.setTable(table); - - - table.setColumns(new Column[]{column, dateColumn}); - table.setDataset(dataset); - table.setLabel("tableLabel"); - table.setName("tableName"); - - column.setTable(table); - - ConceptTreeConnector connector = new ConceptTreeConnector(); - connector.setConcept(concept); - connector.setLabel("connLabel"); - connector.setName("connName"); - connector.setColumn(column); - - concept.setConnectors(List.of(connector)); - - ValidityDate valDate = new ValidityDate(); - valDate.setColumn(dateColumn); - valDate.setConnector(connector); - valDate.setLabel("valLabel"); - valDate.setName("valName"); - connector.setValidityDates(List.of(valDate)); CentralRegistry registry = getMetaStorage().getCentralRegistry(); + Dataset dataset = createDataset(registry); - registry.register(dataset); - registry.register(concept); - registry.register(column); - registry.register(dateColumn); - registry.register(table); - registry.register(connector); - registry.register(valDate); + TreeConcept concept = createConcept(registry, dataset); SerializationTestUtil .forType(TreeConcept.class) @@ -344,6 +298,7 @@ public void treeConcept() throws IOException, JSONException { .test(concept); } + @Test public void persistentIdMap() throws JSONException, IOException { SerializationTestUtil.forType(EntityIdMap.class) @@ -356,9 +311,7 @@ public void persistentIdMap() throws JSONException, IOException { public void formConfig() throws JSONException, IOException { final CentralRegistry registry = getMetaStorage().getCentralRegistry(); - final Dataset dataset = new Dataset("test-dataset"); - - registry.register(dataset); + final Dataset dataset = createDataset(registry); ExportForm form = new ExportForm(); AbsoluteMode mode = new AbsoluteMode(); @@ -400,6 +353,45 @@ public void managedQuery() throws JSONException, IOException { .test(execution); } + @Test + public void testExportForm() throws JSONException, IOException { + + final CentralRegistry registry = getMetaStorage().getCentralRegistry(); + + final Dataset dataset = createDataset(registry); + + + registry.register(dataset); + + final ExportForm exportForm = createExportForm(registry, dataset); + + SerializationTestUtil.forType(QueryDescription.class) + .objectMappers(getManagerInternalMapper(), getApiMapper()) + .registry(registry) + .checkHashCode() + .test(exportForm); + } + + @Test + public void managedForm() throws JSONException, IOException { + + final CentralRegistry registry = getMetaStorage().getCentralRegistry(); + + final Dataset dataset = createDataset(registry); + + final User user = createUser(registry, getMetaStorage()); + + final ExportForm exportForm = createExportForm(registry, dataset); + + ManagedInternalForm execution = new ManagedInternalForm<>(exportForm, user, dataset, getMetaStorage()); + execution.setTags(new String[]{"test-tag"}); + + SerializationTestUtil.forType(ManagedExecution.class) + .objectMappers(getManagerInternalMapper(), getApiMapper()) + .registry(registry) + .test(execution); + } + @Test public void cqConcept() throws JSONException, IOException { diff --git a/backend/src/test/java/com/bakdata/conquery/models/types/SerialisationObjectsUtil.java b/backend/src/test/java/com/bakdata/conquery/models/types/SerialisationObjectsUtil.java new file mode 100644 index 0000000000..a27126bd39 --- /dev/null +++ b/backend/src/test/java/com/bakdata/conquery/models/types/SerialisationObjectsUtil.java @@ -0,0 +1,130 @@ +package com.bakdata.conquery.models.types; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import com.bakdata.conquery.apiv1.forms.export_form.AbsoluteMode; +import com.bakdata.conquery.apiv1.forms.export_form.ExportForm; +import com.bakdata.conquery.apiv1.query.concept.filter.CQTable; +import com.bakdata.conquery.apiv1.query.concept.specific.CQConcept; +import com.bakdata.conquery.io.storage.MetaStorage; +import com.bakdata.conquery.models.auth.entities.User; +import com.bakdata.conquery.models.common.Range; +import com.bakdata.conquery.models.datasets.Column; +import com.bakdata.conquery.models.datasets.Dataset; +import com.bakdata.conquery.models.datasets.Table; +import com.bakdata.conquery.models.datasets.concepts.ValidityDate; +import com.bakdata.conquery.models.datasets.concepts.tree.ConceptTreeConnector; +import com.bakdata.conquery.models.datasets.concepts.tree.TreeConcept; +import com.bakdata.conquery.models.events.MajorTypeId; +import com.bakdata.conquery.models.forms.util.ResolutionShortNames; +import com.bakdata.conquery.models.identifiable.CentralRegistry; +import com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId; +import com.fasterxml.jackson.databind.node.TextNode; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +/** + * Helper class for nested objects needed in {@link com.bakdata.conquery.models.SerializationTests} + */ +@UtilityClass +public class SerialisationObjectsUtil { + + + @NotNull + public static Dataset createDataset(CentralRegistry registry) { + final Dataset dataset = new Dataset("test-dataset"); + registry.register(dataset); + return dataset; + } + + @NotNull + public static TreeConcept createConcept(CentralRegistry registry, Dataset dataset) { + TreeConcept concept = new TreeConcept(); + concept.setDataset(dataset); + concept.setLabel("conceptLabel"); + concept.setName("conceptName"); + + Table table = new Table(); + + Column column = new Column(); + column.setLabel("colLabel"); + column.setName("colName"); + column.setType(MajorTypeId.STRING); + column.setTable(table); + + Column dateColumn = new Column(); + dateColumn.setLabel("colLabel2"); + dateColumn.setName("colName2"); + dateColumn.setType(MajorTypeId.DATE); + dateColumn.setTable(table); + + + table.setColumns(new Column[]{column, dateColumn}); + table.setDataset(dataset); + table.setLabel("tableLabel"); + table.setName("tableName"); + + column.setTable(table); + + ConceptTreeConnector connector = new ConceptTreeConnector(); + connector.setConcept(concept); + connector.setLabel("connLabel"); + connector.setName("connName"); + connector.setColumn(column); + + concept.setConnectors(List.of(connector)); + + ValidityDate valDate = new ValidityDate(); + valDate.setColumn(dateColumn); + valDate.setConnector(connector); + valDate.setLabel("valLabel"); + valDate.setName("valName"); + connector.setValidityDates(List.of(valDate)); + + registry.register(concept); + registry.register(column); + registry.register(dateColumn); + registry.register(table); + registry.register(connector); + registry.register(valDate); + return concept; + } + + @NotNull + public static ExportForm createExportForm(CentralRegistry registry, Dataset dataset) { + final TreeConcept concept = createConcept(registry, dataset); + final ExportForm exportForm = new ExportForm(); + final AbsoluteMode mode = new AbsoluteMode(); + mode.setDateRange(new Range<>(LocalDate.of(2200, 6, 1), LocalDate.of(2200, 6, 2))); + mode.setForm(exportForm); + + final CQConcept cqConcept = new CQConcept(); + + final CQTable table = new CQTable(); + table.setConcept(cqConcept); + table.setConnector(concept.getConnectors().get(0)); + + // Use ArrayList instead of ImmutalbeList here because they use different hash code implementations + cqConcept.setTables(new ArrayList<>(List.of(table))); + cqConcept.setElements(new ArrayList<>(List.of(concept))); + + exportForm.setTimeMode(mode); + exportForm.setFeatures(new ArrayList<>(List.of(cqConcept))); + exportForm.setValues(new TextNode("Some Node")); + exportForm.setQueryGroupId(new ManagedExecutionId(dataset.getId(), UUID.randomUUID())); + exportForm.setResolution(new ArrayList<>(List.of(ResolutionShortNames.COMPLETE))); + return exportForm; + } + + @NotNull + public static User createUser(CentralRegistry registry, MetaStorage storage) { + final User user = new User("test-user", "test-user", storage); + registry.register(user); + + user.updateStorage(); + return user; + } +} From f8133892a8aeec71c8c102339e13a894bae3b8bf Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:29:15 +0100 Subject: [PATCH 2/6] adds impl note to type choice Signed-off-by: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> --- .../models/forms/managed/ManagedForm.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java index 128e6be1de..d476b373ec 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java +++ b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.OptBoolean; +import com.fasterxml.jackson.databind.DatabindContext; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -29,8 +30,19 @@ @CPSType(id = "MANAGED_FORM", base = ManagedExecution.class) public abstract class ManagedForm extends ManagedExecution { + /** + * The submitted form for this execution. + * + * @implNote We use the type {@link Form} here rather than the type parameter F. + * Using F causes the class to have a concrete type at runtime which in turn skips + * the object inspection of Jackson to look at the actual type member of the object (see {@link com.bakdata.conquery.io.cps.CPSTypeIdResolver#typeFromId(DatabindContext, String)}). + * This causes a problem, when the object uses types with {@link com.bakdata.conquery.io.cps.SubTyped}, + * as the subtype is only added to the {@link com.fasterxml.jackson.databind.DeserializationContext}, when the + * type is derived from the
type
member not when Jackson can just infere the deserializer from the type of + * this property. + */ @Getter - private F submittedForm; + private Form submittedForm; protected ManagedForm(@JacksonInject(useInput = OptBoolean.FALSE) MetaStorage storage) { super(storage); @@ -70,7 +82,7 @@ public void visit(Consumer visitor) { @Override @JsonIgnore public F getSubmitted() { - return submittedForm; + return (F) submittedForm; } From f8e8ba24a165582fe54200a777f2968025d0ba09 Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:30:20 +0100 Subject: [PATCH 3/6] fix typo Signed-off-by: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> --- .../com/bakdata/conquery/models/forms/managed/ManagedForm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java index d476b373ec..410460a5ac 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java +++ b/backend/src/main/java/com/bakdata/conquery/models/forms/managed/ManagedForm.java @@ -38,7 +38,7 @@ public abstract class ManagedForm extends ManagedExecution { * the object inspection of Jackson to look at the actual type member of the object (see {@link com.bakdata.conquery.io.cps.CPSTypeIdResolver#typeFromId(DatabindContext, String)}). * This causes a problem, when the object uses types with {@link com.bakdata.conquery.io.cps.SubTyped}, * as the subtype is only added to the {@link com.fasterxml.jackson.databind.DeserializationContext}, when the - * type is derived from the
type
member not when Jackson can just infere the deserializer from the type of + * type is derived from the
type
member not when Jackson can just infer the deserializer from the type of * this property. */ @Getter From 4e44f9d4af9ba51ee9739b06a0ea53bc90aef092 Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:10:24 +0100 Subject: [PATCH 4/6] annotate back references with EqualsAndHashCode.Exclude to avoid Stackoverflow Signed-off-by: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> --- .../com/bakdata/conquery/models/datasets/Column.java | 2 ++ .../bakdata/conquery/models/datasets/ImportColumn.java | 5 ++++- .../models/datasets/concepts/StructureNode.java | 5 +++-- .../models/datasets/concepts/ValidityDate.java | 2 ++ .../models/datasets/concepts/filters/Filter.java | 1 + .../models/datasets/concepts/select/Select.java | 10 +++++++--- .../datasets/concepts/tree/ConceptTreeChild.java | 2 ++ 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java index fa6743eaa7..e6a5c79298 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.base.Preconditions; import io.dropwizard.validation.ValidationMethod; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -42,6 +43,7 @@ public class Column extends Labeled implements NamespacedIdentifiable< @JsonBackReference @NotNull + @EqualsAndHashCode.Exclude private Table table; @NotNull private MajorTypeId type; diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/ImportColumn.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/ImportColumn.java index 81897a6aa2..598cb307cd 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/ImportColumn.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/ImportColumn.java @@ -11,13 +11,16 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; @Data @RequiredArgsConstructor(onConstructor_ = {@JsonCreator}) public class ImportColumn extends NamedImpl implements NamespacedIdentifiable { // TODO reduce usage of this class, it does nothing except hold a description - @JsonBackReference @NotNull + @JsonBackReference + @NotNull + @EqualsAndHashCode.Exclude private final Import parent; // Only used on ManagerNode for com.bakdata.conquery.models.datasets.concepts.filters.specific.AbstractSelectFilter.addImport diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/StructureNode.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/StructureNode.java index 9b96172fe8..42c74d823d 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/StructureNode.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/StructureNode.java @@ -7,15 +7,15 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import com.bakdata.conquery.io.jackson.serializer.NsIdRef; import com.bakdata.conquery.apiv1.KeyValue; +import com.bakdata.conquery.io.jackson.serializer.NsIdRef; import com.bakdata.conquery.models.datasets.Dataset; import com.bakdata.conquery.models.identifiable.Labeled; import com.bakdata.conquery.models.identifiable.ids.specific.ConceptId; import com.bakdata.conquery.models.identifiable.ids.specific.StructureNodeId; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonManagedReference; - +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -32,6 +32,7 @@ public class StructureNode extends Labeled { @Valid @JsonManagedReference(MANAGED_STRUCTURE_STRUCTURE) private List children = Collections.emptyList(); @JsonBackReference(MANAGED_STRUCTURE_STRUCTURE) + @EqualsAndHashCode.Exclude private StructureNode parent; @Getter private LinkedHashSet containedRoots = new LinkedHashSet<>(); diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/ValidityDate.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/ValidityDate.java index a827c86e47..5bdbe1c8bf 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/ValidityDate.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/ValidityDate.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; import io.dropwizard.validation.ValidationMethod; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -26,6 +27,7 @@ public class ValidityDate extends Labeled implements NamespacedI @NotNull private Column column; @JsonBackReference + @EqualsAndHashCode.Exclude private Connector connector; @Override diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java index 243d90f8e1..4447e29f9f 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/Filter.java @@ -39,6 +39,7 @@ public abstract class Filter extends Labeled implements @JsonAlias("description") private String tooltip; @JsonBackReference + @EqualsAndHashCode.Exclude private Connector connector; private String pattern; private Boolean allowDropFile; diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java index 8164e12a25..182d13ab59 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/select/Select.java @@ -28,13 +28,16 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -@JsonTypeInfo(use=JsonTypeInfo.Id.CUSTOM, property="type") +@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type") @CPSBase @Slf4j @EqualsAndHashCode(callSuper = true) public abstract class Select extends Labeled implements NamespacedIdentifiable { - @JsonBackReference @Getter @Setter + @EqualsAndHashCode.Exclude + @JsonBackReference + @Getter + @Setter private SelectHolder holder; @JsonIgnore @@ -43,7 +46,8 @@ public Dataset getDataset() { return getHolder().findConcept().getDataset(); } - @Setter @Getter + @Setter + @Getter private String description; /** diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/tree/ConceptTreeChild.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/tree/ConceptTreeChild.java index 829eed8120..7e941a607d 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/tree/ConceptTreeChild.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/tree/ConceptTreeChild.java @@ -14,6 +14,7 @@ import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonManagedReference; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -32,6 +33,7 @@ public class ConceptTreeChild extends ConceptElement impleme @JsonBackReference @Getter @Setter + @EqualsAndHashCode.Exclude private ConceptTreeNode parent; @JsonIgnore @Getter From f809860296e79d7e0bc96ac1254964097ddd5b80 Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Fri, 17 Mar 2023 09:24:10 +0100 Subject: [PATCH 5/6] SerializationTestUtil compare only id of deserialized object not hash code Signed-off-by: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> --- .../conquery/models/datasets/concepts/Connector.java | 1 - .../bakdata/conquery/models/worker/WorkerInformation.java | 5 ++++- .../io/jackson/serializer/SerializationTestUtil.java | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Connector.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Connector.java index 6f4689c762..b9b73e1a7c 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Connector.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Connector.java @@ -42,7 +42,6 @@ @Valid @Slf4j @JsonIgnoreProperties({"defaultForEntityPreview"}) -@EqualsAndHashCode(callSuper = true) public abstract class Connector extends Labeled implements SelectHolder