From 16a872ec931876aff7d2a7b32ce566c02f7cbae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 10 May 2023 15:59:23 +0100 Subject: [PATCH 01/10] Add @JsonMerge annotations recursively to Activity POJO --- .../src/main/java/dev/learning/xapi/model/Activity.java | 2 ++ .../main/java/dev/learning/xapi/model/ActivityDefinition.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Activity.java b/xapi-model/src/main/java/dev/learning/xapi/model/Activity.java index d56059a9..76de8aaf 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Activity.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Activity.java @@ -4,6 +4,7 @@ package dev.learning.xapi.model; +import com.fasterxml.jackson.annotation.JsonMerge; import dev.learning.xapi.model.validation.constraints.ValidActivityDefinition; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; @@ -40,6 +41,7 @@ public class Activity implements StatementObject, SubStatementObject { */ @Valid @ValidActivityDefinition + @JsonMerge private ActivityDefinition definition; // **Warning** do not add fields that are not required by the xAPI specification. diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java b/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java index dee40d07..113ab876 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonMerge; import dev.learning.xapi.model.validation.constraints.HasScheme; import java.net.URI; import java.util.ArrayList; @@ -33,11 +34,13 @@ public class ActivityDefinition { /** * The human readable/visual name of the Activity. */ + @JsonMerge private LanguageMap name; /** * A description of the Activity. */ + @JsonMerge private LanguageMap description; /** @@ -90,6 +93,7 @@ public class ActivityDefinition { /** * A map of other properties as needed. */ + @JsonMerge private Map<@HasScheme URI, Object> extensions; // **Warning** do not add fields that are not required by the xAPI From 63420e912f62138e54e3c69a5d64559b281c69e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 10 May 2023 16:59:34 +0100 Subject: [PATCH 02/10] Add test for merging activities --- .../learning/xapi/model/ActivityTests.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index 772bad52..59ff840b 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -8,12 +8,16 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import dev.learning.xapi.jackson.XapiStrictLocaleModule; import java.io.IOException; import java.net.URI; +import java.util.Collections; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -159,4 +163,62 @@ void whenDeserializingActivityWithInvalidDisplayThenResultIsExpected() throws Ex } + @Test + void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { + + final var uriA = URI.create("http://example.com/aaa"); + final var uriB = URI.create("http://example.com/bbb"); + final var uriMap = URI.create("http://example.com/map"); + + // When Two Activities Are Merged + final var map1 = new HashMap(); + map1.put(uriA, "aaa"); + map1.put(uriMap, new HashMap<>(Collections.singletonMap("aaa", "aaa"))); + + final var activity1 = Activity.builder().definition(d -> d + + .addName(Locale.US, "name-US") + + .addDescription(Locale.US, "description-US") + + .extensions(map1) + + ).build(); + + final var map2 = new HashMap(); + map2.put(uriB, "bbb"); + map2.put(uriMap, new HashMap<>(Collections.singletonMap("bbb", "bbb"))); + + final var activity2 = Activity.builder().definition(d -> d + + .addName(Locale.UK, "name-UK") + + .addDescription(Locale.UK, "description-UK") + + .extensions(map2) + + ).build(); + + final var updater = objectMapper.readerForUpdating(activity1) + .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + final var merged = (Activity) updater.readValue(objectMapper.writeValueAsString(activity2)); + + // Then Result Is Expected + assertThat(merged.getDefinition().getName().get(Locale.US), is("name-US")); + assertThat(merged.getDefinition().getName().get(Locale.UK), is("name-UK")); + + assertThat(merged.getDefinition().getDescription().get(Locale.US), is("description-US")); + assertThat(merged.getDefinition().getDescription().get(Locale.UK), is("description-UK")); + + assertThat(merged.getDefinition().getExtensions().get(uriA), is("aaa")); + assertThat(merged.getDefinition().getExtensions().get(uriB), is("bbb")); + + @SuppressWarnings("unchecked") + final var deepMap = (Map) merged.getDefinition().getExtensions().get(uriMap); + + assertThat(deepMap.get("aaa"), is("aaa")); + assertThat(deepMap.get("bbb"), is("bbb")); + + } + } From 9091d063b252f997bfb5ceb7204ef54ada8dd3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Fri, 12 May 2023 16:29:48 +0100 Subject: [PATCH 03/10] add @JsonIgnoreProperties("objectType") to polymorphic classes --- .../src/main/java/dev/learning/xapi/model/Actor.java | 2 ++ .../java/dev/learning/xapi/model/StatementObject.java | 2 ++ .../java/dev/learning/xapi/model/SubStatementObject.java | 2 ++ .../test/java/dev/learning/xapi/model/ActivityTests.java | 9 ++++++--- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java b/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java index 8d8d8bc7..d522bac3 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java @@ -4,6 +4,7 @@ package dev.learning.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; @@ -39,6 +40,7 @@ @JsonSubTypes.Type(value = Agent.class, name = "Person"), @JsonSubTypes.Type(value = Group.class, name = "Group")}) @JsonInclude(Include.NON_EMPTY) +@JsonIgnoreProperties("objectType") public abstract class Actor implements StatementObject, SubStatementObject { /** diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/StatementObject.java b/xapi-model/src/main/java/dev/learning/xapi/model/StatementObject.java index f381c5ab..9a683898 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/StatementObject.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/StatementObject.java @@ -4,6 +4,7 @@ package dev.learning.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonSubTypes; @@ -26,6 +27,7 @@ @JsonSubTypes.Type(value = Group.class, name = "Group"), @JsonSubTypes.Type(value = SubStatement.class, name = "SubStatement"), @JsonSubTypes.Type(value = StatementReference.class, name = "StatementRef")}) +@JsonIgnoreProperties("objectType") public interface StatementObject { } diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/SubStatementObject.java b/xapi-model/src/main/java/dev/learning/xapi/model/SubStatementObject.java index 457b2ad2..8f46ad2f 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/SubStatementObject.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/SubStatementObject.java @@ -4,6 +4,7 @@ package dev.learning.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonSubTypes; @@ -28,6 +29,7 @@ @JsonSubTypes.Type(value = Agent.class, name = "Agent"), @JsonSubTypes.Type(value = Group.class, name = "Group"), @JsonSubTypes.Type(value = StatementReference.class, name = "StatementRef")}) +@JsonIgnoreProperties("objectType") public interface SubStatementObject { } diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index 59ff840b..517a9e84 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -8,7 +8,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import dev.learning.xapi.jackson.XapiStrictLocaleModule; @@ -199,8 +198,12 @@ void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { ).build(); - final var updater = objectMapper.readerForUpdating(activity1) - .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + final var a = objectMapper.writeValueAsString(activity1); + System.err.println(activity1); + System.err.println(objectMapper.readValue(a, Activity.class)); + System.err.println(a); + + final var updater = objectMapper.readerForUpdating(activity1); final var merged = (Activity) updater.readValue(objectMapper.writeValueAsString(activity2)); // Then Result Is Expected From 1b2313cb1fc1eb087dce2019f0ceef575effa9b0 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 12 May 2023 16:44:08 +0100 Subject: [PATCH 04/10] tip --- xapi-model/pom.xml | 139 +++++++++--------- .../xapi/model/ActivityDefinition.java | 11 ++ .../xapi/model/ActivityDefinitionTests.java | 119 ++++++++++++++- .../learning/xapi/model/ActivityTests.java | 59 +++----- 4 files changed, 221 insertions(+), 107 deletions(-) diff --git a/xapi-model/pom.xml b/xapi-model/pom.xml index d2b186e4..b01251c9 100644 --- a/xapi-model/pom.xml +++ b/xapi-model/pom.xml @@ -1,68 +1,75 @@ - - 4.0.0 - - dev.learning.xapi - xapi-build - 1.1.6-SNAPSHOT - - xapi-model - xAPI Model - learning.dev xAPI Model - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - true - - - io.jsonwebtoken - jjwt-jackson - true - - - com.fasterxml.jackson.core - jackson-databind - - - org.projectlombok - lombok - provided - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - jakarta.validation - jakarta.validation-api - - - org.hibernate.validator - hibernate-validator - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-validation - test - - - - - - org.jacoco - jacoco-maven-plugin - - - + + 4.0.0 + + dev.learning.xapi + xapi-build + 1.1.6-SNAPSHOT + + xapi-model + xAPI Model + learning.dev xAPI Model + + + io.jsonwebtoken + jjwt-api + + + io.jsonwebtoken + jjwt-impl + true + + + io.jsonwebtoken + jjwt-jackson + true + + + com.fasterxml.jackson.core + jackson-databind + + + org.projectlombok + lombok + provided + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + jakarta.validation + jakarta.validation-api + + + org.hibernate.validator + hibernate-validator + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + test + + + org.springframework.integration + spring-integration-test + test + + + + + + org.jacoco + jacoco-maven-plugin + + + diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java b/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java index 113ab876..93d25acd 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/ActivityDefinition.java @@ -19,12 +19,23 @@ /** * This class represents the xAPI Activity Definition object. + *

+ * Upon receiving a Statement with an Activity Definition that differs from the one stored, an LRS + * SHOULD ... change the definition and SHOULD update the stored Activity Definition. + *

+ *

+ * When two ActivityDefinitions are merged, the properties and lists are replaced and the maps are + * merged. + *

* * @author Thomas Turrell-Croft * * @see xAPI * Activity Definition + * @see LRS + * Requirements */ @Value @Builder diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityDefinitionTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityDefinitionTests.java index 83eade6d..490e2521 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityDefinitionTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityDefinitionTests.java @@ -9,16 +9,21 @@ import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.springframework.integration.test.matcher.MapContentMatchers.hasAllEntries; import com.fasterxml.jackson.databind.ObjectMapper; +import dev.learning.xapi.model.validation.constraints.HasScheme; import java.io.IOException; import java.net.URI; import java.util.Collections; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.util.ResourceUtils; + /** * Activity Definition Tests. * @@ -331,8 +336,7 @@ void whenSerializingActivityDefinitionOfInteractionTypeTrueFalseThenResultIsEqua .build(); // When Serializing Activity Definition Of InteractionType True False - final var result = - objectMapper.readTree(objectMapper.writeValueAsString(activityDefinition)); + final var result = objectMapper.readTree(objectMapper.writeValueAsString(activityDefinition)); // Then Result Is Equal To Expected Json assertThat(result, is(objectMapper @@ -367,8 +371,7 @@ void whenSerializingActivityDefinitionOfInteractionTypeChoiceThenResultIsEqualTo .build(); // When Serializing Activity Definition Of InteractionType Choice - final var result = - objectMapper.readTree(objectMapper.writeValueAsString(activityDefinition)); + final var result = objectMapper.readTree(objectMapper.writeValueAsString(activityDefinition)); // Then Result Is Equal To Expected Json assertThat(result, is( @@ -441,4 +444,112 @@ void whenBuildingActivityDefinitionWithTwoDescriptionValuesThenDescriptionLangua } + @Test + void whenMergingActivityDefinitionsWithNamesThenMergedNameIsExpected() throws IOException { + + final var activityDefinition1 = + ActivityDefinition.builder().addName(Locale.UK, "Colour").build(); + + final var x = + objectMapper.valueToTree(ActivityDefinition.builder().addName(Locale.US, "Color").build()); + + final var expected = new LanguageMap(); + expected.put(Locale.UK, "Colour"); + expected.put(Locale.US, "Color"); + + // When Merging ActivityDefinitions With Names + final var merged = + (ActivityDefinition) objectMapper.readerForUpdating(activityDefinition1).readValue(x); + + // Then Merged Name Is Expected + assertThat(merged.getName(), hasAllEntries(expected)); + + } + + @Test + void whenMergingActivityDefinitionsWithDescriptionsThenMergedDescriptionIsExpected() + throws IOException { + + final var activityDefinition1 = + ActivityDefinition.builder().addDescription(Locale.UK, "flavour").build(); + + final var x = objectMapper + .valueToTree(ActivityDefinition.builder().addDescription(Locale.US, "flavor").build()); + + final var expected = new LanguageMap(); + expected.put(Locale.UK, "flavour"); + expected.put(Locale.US, "flavor"); + + // When Merging ActivityDefinitions With Descriptions + final var merged = + (ActivityDefinition) objectMapper.readerForUpdating(activityDefinition1).readValue(x); + + // Then Merged Description Is Expected + assertThat(merged.getDescription(), hasAllEntries(expected)); + + } + + @Test + void whenMergingActivityDefinitionsWithExtensionsThenMergedExtensionsAreExpected() + throws IOException { + + final Map<@HasScheme URI, Object> extensions1 = new HashMap<>(); + extensions1.put(URI.create("https://example.com/extensions/1"), "1"); + + final var activityDefinition1 = ActivityDefinition.builder().addName(Locale.UK, "Colour") + .addDescription(Locale.UK, "flavour").extensions(extensions1).build(); + + final Map<@HasScheme URI, Object> extensions2 = new HashMap<>(); + extensions2.put(URI.create("https://example.com/extensions/2"), "2"); + + final var x = objectMapper.valueToTree(ActivityDefinition.builder().addName(Locale.US, "Color") + .addDescription(Locale.US, "flavor").extensions(extensions2).build()); + + final Map<@HasScheme URI, Object> expected = new HashMap<>(); + expected.put(URI.create("https://example.com/extensions/1"), "1"); + expected.put(URI.create("https://example.com/extensions/2"), "2"); + + // When Merging ActivityDefinitions With Extensions + final var merged = + (ActivityDefinition) objectMapper.readerForUpdating(activityDefinition1).readValue(x); + + // Then Merged Extensions Are Expected + assertThat(merged.getExtensions(), hasAllEntries(expected)); + + } + + @Test + void whenMergingActivityDefinitionsWithNestedExtensionsThenMergedExtensionsAreExpected() + throws IOException { + + final Map<@HasScheme URI, Object> extensions1 = new HashMap<>(); + extensions1.put(URI.create("https://example.com/extensions/map"), + new HashMap<>(Collections.singletonMap("a", "y"))); + + final var activityDefinition1 = ActivityDefinition.builder().extensions(extensions1).build(); + + final Map<@HasScheme URI, Object> extensions2 = new HashMap<>(); + extensions2.put(URI.create("https://example.com/extensions/map"), + new HashMap<>(Collections.singletonMap("b", "z"))); + + final var x = + objectMapper.valueToTree(ActivityDefinition.builder().extensions(extensions2).build()); + + final Map expected = new HashMap<>(); + expected.put("a", "y"); + expected.put("b", "z"); + + // When Merging ActivityDefinitions With Nested Extensions + final var merged = + (ActivityDefinition) objectMapper.readerForUpdating(activityDefinition1).readValue(x); + + @SuppressWarnings("unchecked") + final var po = (Map) merged.getExtensions() + .get(URI.create("https://example.com/extensions/map")); + + // Then Merged Extensions Are Expected + assertThat(po, hasAllEntries(expected)); + + } + } diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index 59ff840b..2fe7af4e 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -8,7 +8,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import dev.learning.xapi.jackson.XapiStrictLocaleModule; @@ -17,7 +16,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Locale; -import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -166,58 +164,45 @@ void whenDeserializingActivityWithInvalidDisplayThenResultIsExpected() throws Ex @Test void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { - final var uriA = URI.create("http://example.com/aaa"); - final var uriB = URI.create("http://example.com/bbb"); - final var uriMap = URI.create("http://example.com/map"); - - // When Two Activities Are Merged - final var map1 = new HashMap(); - map1.put(uriA, "aaa"); - map1.put(uriMap, new HashMap<>(Collections.singletonMap("aaa", "aaa"))); - final var activity1 = Activity.builder().definition(d -> d - .addName(Locale.US, "name-US") + .addName(Locale.US, "Color") - .addDescription(Locale.US, "description-US") + .addDescription(Locale.US, "flavor") - .extensions(map1) + .extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/a"), "a"))) ).build(); - final var map2 = new HashMap(); - map2.put(uriB, "bbb"); - map2.put(uriMap, new HashMap<>(Collections.singletonMap("bbb", "bbb"))); + final var x = objectMapper.valueToTree(Activity.builder().definition(d -> d - final var activity2 = Activity.builder().definition(d -> d + .addName(Locale.UK, "Colour") - .addName(Locale.UK, "name-UK") + .addDescription(Locale.UK, "flavour") - .addDescription(Locale.UK, "description-UK") + .extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/b"), "b")) - .extensions(map2) + )).build()); - ).build(); - - final var updater = objectMapper.readerForUpdating(activity1) - .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - final var merged = (Activity) updater.readValue(objectMapper.writeValueAsString(activity2)); + // When Merging Activities With ActivityDefinitions + final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); // Then Result Is Expected - assertThat(merged.getDefinition().getName().get(Locale.US), is("name-US")); - assertThat(merged.getDefinition().getName().get(Locale.UK), is("name-UK")); - - assertThat(merged.getDefinition().getDescription().get(Locale.US), is("description-US")); - assertThat(merged.getDefinition().getDescription().get(Locale.UK), is("description-UK")); + assertThat(merged.getDefinition().getName().get(Locale.US), is("Color")); + assertThat(merged.getDefinition().getName().get(Locale.UK), is("Colour")); - assertThat(merged.getDefinition().getExtensions().get(uriA), is("aaa")); - assertThat(merged.getDefinition().getExtensions().get(uriB), is("bbb")); + assertThat(merged.getDefinition().getDescription().get(Locale.US), is("flavor")); + assertThat(merged.getDefinition().getDescription().get(Locale.UK), is("flavour")); - @SuppressWarnings("unchecked") - final var deepMap = (Map) merged.getDefinition().getExtensions().get(uriMap); + assertThat( + merged.getDefinition().getExtensions().get(URI.create("https://example.com/extensions/a")), + is("a")); + assertThat( + merged.getDefinition().getExtensions().get(URI.create("https://example.com/extensions/b")), + is("b")); - assertThat(deepMap.get("aaa"), is("aaa")); - assertThat(deepMap.get("bbb"), is("bbb")); } From 4e65607cad4fbda476e6722f06fe910bb3250cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Fri, 12 May 2023 16:45:02 +0100 Subject: [PATCH 05/10] oops --- .../src/test/java/dev/learning/xapi/model/ActivityTests.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index 517a9e84..0ab38664 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -198,11 +198,6 @@ void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { ).build(); - final var a = objectMapper.writeValueAsString(activity1); - System.err.println(activity1); - System.err.println(objectMapper.readValue(a, Activity.class)); - System.err.println(a); - final var updater = objectMapper.readerForUpdating(activity1); final var merged = (Activity) updater.readValue(objectMapper.writeValueAsString(activity2)); From 2e344c972e03231006df8da90b08911456513610 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 12 May 2023 17:34:55 +0100 Subject: [PATCH 06/10] tip --- .../learning/xapi/model/ActivityTests.java | 79 +++++++++++++++---- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index 2fe7af4e..a98cf06b 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -7,15 +7,18 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.springframework.integration.test.matcher.MapContentMatchers.hasAllEntries; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import dev.learning.xapi.jackson.XapiStrictLocaleModule; +import dev.learning.xapi.model.validation.constraints.HasScheme; import java.io.IOException; import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.Locale; +import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -164,9 +167,28 @@ void whenDeserializingActivityWithInvalidDisplayThenResultIsExpected() throws Ex @Test void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { - final var activity1 = Activity.builder().definition(d -> d + final var activity1 = Activity.builder().definition(d -> d.addName(Locale.US, "Color")).build(); + + final var x = objectMapper + .valueToTree(Activity.builder().definition(d -> d.addName(Locale.UK, "Colour")).build()); + + final var expected = new LanguageMap(); + expected.put(Locale.UK, "Colour"); + expected.put(Locale.US, "Color"); + + // When Merging Activities With ActivityDefinitions With Names + final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); - .addName(Locale.US, "Color") + // Then Merged Name Is Expected + assertThat(merged.getDefinition().getName(), hasAllEntries(expected)); + + } + + @Test + void whenMergingActivitiesWithActivityDefinitionsWithDescriptionsThenMergedDefinitionIsExpected() + throws IOException { + + final var activity1 = Activity.builder().definition(d -> d .addDescription(Locale.US, "flavor") @@ -177,8 +199,6 @@ void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { final var x = objectMapper.valueToTree(Activity.builder().definition(d -> d - .addName(Locale.UK, "Colour") - .addDescription(Locale.UK, "flavour") .extensions(new HashMap<>( @@ -186,24 +206,51 @@ void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { )).build()); - // When Merging Activities With ActivityDefinitions + final var expected = new LanguageMap(); + expected.put(Locale.UK, "flavor"); + expected.put(Locale.US, "flavour"); + + // When Merging Activities With ActivityDefinitions With Descriptions final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); - // Then Result Is Expected - assertThat(merged.getDefinition().getName().get(Locale.US), is("Color")); - assertThat(merged.getDefinition().getName().get(Locale.UK), is("Colour")); + // Then Merged Definition Is Expected + assertThat(merged.getDefinition().getDescription(), hasAllEntries(expected)); + + } + + @Test + void whenMergingActivitiesWithActivityDefinitionsWithExtensionsThenMergedExtensionIsExpected() + throws IOException { + + final var activity1 = Activity.builder().definition(d -> d + + .addDescription(Locale.US, "flavor") + + .extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/a"), "a"))) - assertThat(merged.getDefinition().getDescription().get(Locale.US), is("flavor")); - assertThat(merged.getDefinition().getDescription().get(Locale.UK), is("flavour")); + ).build(); - assertThat( - merged.getDefinition().getExtensions().get(URI.create("https://example.com/extensions/a")), - is("a")); - assertThat( - merged.getDefinition().getExtensions().get(URI.create("https://example.com/extensions/b")), - is("b")); + final var x = objectMapper.valueToTree(Activity.builder().definition(d -> d + .addDescription(Locale.UK, "flavour") + + .extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/b"), "b")) + + )).build()); + + final Map<@HasScheme URI, Object> expected = new HashMap<>(); + expected.put(URI.create("https://example.com/extensions/a"), "a"); + expected.put(URI.create("https://example.com/extensions/b"), "b"); + + // When Merging Activities With ActivityDefinitions With Extensions + final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); + + // Then Merged Extension Is Expected + assertThat(merged.getDefinition().getExtensions(), hasAllEntries(expected)); } + } From 3834450f78d3e169315ec8072bbd7ffce6f30a7b Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 12 May 2023 17:56:53 +0100 Subject: [PATCH 07/10] Apply suggestions from code review --- .../src/test/java/dev/learning/xapi/model/ActivityTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index a98cf06b..ae073d4d 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -207,8 +207,8 @@ void whenMergingActivitiesWithActivityDefinitionsWithDescriptionsThenMergedDefin )).build()); final var expected = new LanguageMap(); - expected.put(Locale.UK, "flavor"); - expected.put(Locale.US, "flavour"); + expected.put(Locale.UK, "flavour"); + expected.put(Locale.US, "flavor"); // When Merging Activities With ActivityDefinitions With Descriptions final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); From b50db7161a1de780ee4d2f47c5f56f8594aac4df Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sat, 13 May 2023 07:44:36 +0100 Subject: [PATCH 08/10] Change back to space formmating --- xapi-model/pom.xml | 146 ++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/xapi-model/pom.xml b/xapi-model/pom.xml index b01251c9..313318b7 100644 --- a/xapi-model/pom.xml +++ b/xapi-model/pom.xml @@ -1,75 +1,75 @@ - 4.0.0 - - dev.learning.xapi - xapi-build - 1.1.6-SNAPSHOT - - xapi-model - xAPI Model - learning.dev xAPI Model - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - true - - - io.jsonwebtoken - jjwt-jackson - true - - - com.fasterxml.jackson.core - jackson-databind - - - org.projectlombok - lombok - provided - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - jakarta.validation - jakarta.validation-api - - - org.hibernate.validator - hibernate-validator - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-validation - test - - - org.springframework.integration - spring-integration-test - test - - - - - - org.jacoco - jacoco-maven-plugin - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + dev.learning.xapi + xapi-build + 1.1.6-SNAPSHOT + + xapi-model + xAPI Model + learning.dev xAPI Model + + + io.jsonwebtoken + jjwt-api + + + io.jsonwebtoken + jjwt-impl + true + + + io.jsonwebtoken + jjwt-jackson + true + + + com.fasterxml.jackson.core + jackson-databind + + + org.projectlombok + lombok + provided + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + jakarta.validation + jakarta.validation-api + + + org.hibernate.validator + hibernate-validator + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + test + + + org.springframework.integration + spring-integration-test + test + + + + + + org.jacoco + jacoco-maven-plugin + + + +
\ No newline at end of file From b0ff91679273d51af10d357885213b45f675784b Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sat, 13 May 2023 07:46:14 +0100 Subject: [PATCH 09/10] tip --- xapi-model/pom.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xapi-model/pom.xml b/xapi-model/pom.xml index 313318b7..ccc8aead 100644 --- a/xapi-model/pom.xml +++ b/xapi-model/pom.xml @@ -1,7 +1,5 @@ - + 4.0.0 dev.learning.xapi From b8c203f5166e46ba74cc6c8801cf3bf37c2e1200 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sat, 13 May 2023 08:04:15 +0100 Subject: [PATCH 10/10] tip --- .../learning/xapi/model/ActivityTests.java | 47 ++++++------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java index ae073d4d..f48998a7 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ActivityTests.java @@ -165,7 +165,8 @@ void whenDeserializingActivityWithInvalidDisplayThenResultIsExpected() throws Ex } @Test - void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { + void whenMergingActivitiesWithActivityDefinitionsWithNamesThenMergedNameIsExpected() + throws IOException { final var activity1 = Activity.builder().definition(d -> d.addName(Locale.US, "Color")).build(); @@ -188,23 +189,11 @@ void whenTwoActivitiesAreMergedThenResultIsExpected() throws IOException { void whenMergingActivitiesWithActivityDefinitionsWithDescriptionsThenMergedDefinitionIsExpected() throws IOException { - final var activity1 = Activity.builder().definition(d -> d - - .addDescription(Locale.US, "flavor") - - .extensions(new HashMap<>( - Collections.singletonMap(URI.create("https://example.com/extensions/a"), "a"))) - - ).build(); - - final var x = objectMapper.valueToTree(Activity.builder().definition(d -> d - - .addDescription(Locale.UK, "flavour") + final var activity1 = + Activity.builder().definition(d -> d.addDescription(Locale.US, "flavor")).build(); - .extensions(new HashMap<>( - Collections.singletonMap(URI.create("https://example.com/extensions/b"), "b")) - - )).build()); + final var x = objectMapper.valueToTree( + Activity.builder().definition(d -> d.addDescription(Locale.UK, "flavour")).build()); final var expected = new LanguageMap(); expected.put(Locale.UK, "flavour"); @@ -219,26 +208,18 @@ void whenMergingActivitiesWithActivityDefinitionsWithDescriptionsThenMergedDefin } @Test - void whenMergingActivitiesWithActivityDefinitionsWithExtensionsThenMergedExtensionIsExpected() + void whenMergingActivitiesWithActivityDefinitionsWithExtensionsThenMergedExtensionsAreExpected() throws IOException { - final var activity1 = Activity.builder().definition(d -> d - - .addDescription(Locale.US, "flavor") - - .extensions(new HashMap<>( - Collections.singletonMap(URI.create("https://example.com/extensions/a"), "a"))) + final var activity1 = Activity.builder().definition(d -> d.extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/a"), "a"))) ).build(); - final var x = objectMapper.valueToTree(Activity.builder().definition(d -> d - - .addDescription(Locale.UK, "flavour") - - .extensions(new HashMap<>( - Collections.singletonMap(URI.create("https://example.com/extensions/b"), "b")) - - )).build()); + final var x = objectMapper.valueToTree(Activity.builder() + .definition(d -> d.extensions(new HashMap<>( + Collections.singletonMap(URI.create("https://example.com/extensions/b"), "b")))) + .build()); final Map<@HasScheme URI, Object> expected = new HashMap<>(); expected.put(URI.create("https://example.com/extensions/a"), "a"); @@ -247,7 +228,7 @@ void whenMergingActivitiesWithActivityDefinitionsWithExtensionsThenMergedExtensi // When Merging Activities With ActivityDefinitions With Extensions final var merged = (Activity) objectMapper.readerForUpdating(activity1).readValue(x); - // Then Merged Extension Is Expected + // Then Merged Extensions Are Expected assertThat(merged.getDefinition().getExtensions(), hasAllEntries(expected)); }