From e6d18dc65dad26ea345ae39eff1ddc4de359fe53 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Tue, 3 Dec 2024 09:36:11 -0500 Subject: [PATCH 01/22] Add jakarta.validation-api dependency --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 8df8735..6cf5c2f 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,11 @@ json-path 2.9.0 + + jakarta.validation + jakarta.validation-api + 3.1.0 + junit junit From 8680376ebd39918f05660ee9c93b8bf31d7c3d81 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Tue, 3 Dec 2024 15:23:46 -0500 Subject: [PATCH 02/22] Add validation implementation dep --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index 6cf5c2f..1824cb8 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,12 @@ jakarta.validation-api 3.1.0 + + org.apache.bval + bval-jsr + 3.0.1 + + junit junit From cc0de68119649383f6dafbe0f9f666f8c0f880da Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 4 Dec 2024 13:28:59 -0500 Subject: [PATCH 03/22] Remove warnings in model package --- src/main/java/com/yetanalytics/xapi/model/Extensions.java | 8 +++++--- .../java/com/yetanalytics/xapi/model/InteractionType.java | 2 +- src/main/java/com/yetanalytics/xapi/model/LangMap.java | 2 +- src/main/java/com/yetanalytics/xapi/model/ObjectType.java | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/yetanalytics/xapi/model/Extensions.java b/src/main/java/com/yetanalytics/xapi/model/Extensions.java index 10acc0d..09ee477 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Extensions.java +++ b/src/main/java/com/yetanalytics/xapi/model/Extensions.java @@ -24,7 +24,7 @@ @JsonSerialize(using = ExtensionSerializer.class) public class Extensions { - private Map extMap = new HashMap(); + private Map extMap = new HashMap<>(); public Extensions(Map input) { extMap = input; @@ -65,9 +65,11 @@ public T read(String key, String jsonPathExpression, Class typeKey) { return (T) JsonPath.read(json, jsonPathExpression); } catch (PathNotFoundException e) { //TODO: logging framework - e.printStackTrace(); + System.err.println("Path not found"); + // e.printStackTrace(); } catch (JsonProcessingException e) { - e.printStackTrace(); + System.err.println("JSON cannot be processed"); + // e.printStackTrace(); } return null; } diff --git a/src/main/java/com/yetanalytics/xapi/model/InteractionType.java b/src/main/java/com/yetanalytics/xapi/model/InteractionType.java index 0e4bd59..db2f285 100644 --- a/src/main/java/com/yetanalytics/xapi/model/InteractionType.java +++ b/src/main/java/com/yetanalytics/xapi/model/InteractionType.java @@ -21,7 +21,7 @@ public enum InteractionType { NUMERIC("numeric"), OTHER("other"); - private String displayName; + private final String displayName; InteractionType(String displayName) { this.displayName = displayName; diff --git a/src/main/java/com/yetanalytics/xapi/model/LangMap.java b/src/main/java/com/yetanalytics/xapi/model/LangMap.java index a601a4a..cb451a4 100644 --- a/src/main/java/com/yetanalytics/xapi/model/LangMap.java +++ b/src/main/java/com/yetanalytics/xapi/model/LangMap.java @@ -20,7 +20,7 @@ @JsonSerialize(using = LangMapSerializer.class) public class LangMap { - private HashMap languageHashMap = new HashMap(); + private HashMap languageHashMap = new HashMap<>(); /** * Create a new langmap from a HashMap diff --git a/src/main/java/com/yetanalytics/xapi/model/ObjectType.java b/src/main/java/com/yetanalytics/xapi/model/ObjectType.java index 4f91938..7ba66cc 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ObjectType.java +++ b/src/main/java/com/yetanalytics/xapi/model/ObjectType.java @@ -16,7 +16,7 @@ public enum ObjectType { AGENT("Agent"), GROUP("Group"); - private String displayName; + private final String displayName; ObjectType(String displayName) { this.displayName = displayName; From 4b2ba1118d765be4342f1ec5ca55b2d46ad40d3a Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 4 Dec 2024 13:32:50 -0500 Subject: [PATCH 04/22] Remove warning in test case --- .../yetanalytics/XapiDeserializationTest.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/yetanalytics/XapiDeserializationTest.java b/src/test/java/com/yetanalytics/XapiDeserializationTest.java index d43a5b7..ffc6f03 100644 --- a/src/test/java/com/yetanalytics/XapiDeserializationTest.java +++ b/src/test/java/com/yetanalytics/XapiDeserializationTest.java @@ -1,8 +1,8 @@ package com.yetanalytics; +import java.io.File; import java.io.IOException; import java.math.BigDecimal; -import java.io.File; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.LinkedHashMap; @@ -12,7 +12,22 @@ import com.fasterxml.jackson.core.exc.StreamReadException; import com.fasterxml.jackson.databind.DatabindException; import com.yetanalytics.util.TestFileUtils; -import com.yetanalytics.xapi.model.*; +import com.yetanalytics.xapi.model.AbstractActor; +import com.yetanalytics.xapi.model.Activity; +import com.yetanalytics.xapi.model.ActivityDefinition; +import com.yetanalytics.xapi.model.Agent; +import com.yetanalytics.xapi.model.Attachment; +import com.yetanalytics.xapi.model.Context; +import com.yetanalytics.xapi.model.ContextActivities; +import com.yetanalytics.xapi.model.Extensions; +import com.yetanalytics.xapi.model.Group; +import com.yetanalytics.xapi.model.InteractionComponent; +import com.yetanalytics.xapi.model.InteractionType; +import com.yetanalytics.xapi.model.Result; +import com.yetanalytics.xapi.model.Score; +import com.yetanalytics.xapi.model.Statement; +import com.yetanalytics.xapi.model.StatementResult; +import com.yetanalytics.xapi.model.Verb; import com.yetanalytics.xapi.util.Mapper; import junit.framework.Test; @@ -102,7 +117,7 @@ public void testExtensions() throws StreamReadException, DatabindException, IOEx Integer elementNumber = ext.read(extKey, "$.listOfThings[1].number", Integer.class); assertEquals(elementNumber, Integer.valueOf(2)); Double decimalEntry = ext.read(extKey, "$.decimalEntry", Double.class); - assertEquals(decimalEntry, Double.valueOf(3.14159)); + assertEquals(decimalEntry, 3.14159); Boolean boolEntry = ext.read(extKey, "$.boolEntry", Boolean.class); assertEquals(boolEntry, Boolean.TRUE); String nullEntry = ext.read(extKey, "$.nullEntry", String.class); From 847d1b93360e39db4b42892094e35395acd79cc0 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 4 Dec 2024 13:35:47 -0500 Subject: [PATCH 05/22] Remove remaining warnings from xapi model --- src/main/java/com/yetanalytics/xapi/model/XapiDuration.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/yetanalytics/xapi/model/XapiDuration.java b/src/main/java/com/yetanalytics/xapi/model/XapiDuration.java index 870d604..73e0076 100644 --- a/src/main/java/com/yetanalytics/xapi/model/XapiDuration.java +++ b/src/main/java/com/yetanalytics/xapi/model/XapiDuration.java @@ -3,9 +3,9 @@ import java.time.Duration; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonValue; /** * Class representation of ISO 8601 Duration @@ -26,9 +26,9 @@ public XapiDuration(String duration){ this.duration = Duration.parse(duration); } - private String original; + private final String original; - private Duration duration; + private final Duration duration; /** * Returns the original String version of the Duration From fa031cd4b02aa5f3b79602f783175923beecdc95 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:14:30 -0500 Subject: [PATCH 06/22] Add validation that Agents only have 1 IFI --- .../xapi/model/AbstractActor.java | 21 +++++- .../com/yetanalytics/xapi/model/Agent.java | 11 ++++ .../com/yetanalytics/model/AgentTest.java | 65 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/yetanalytics/model/AgentTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java index 331d33b..bc92abc 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java @@ -11,12 +11,13 @@ public abstract class AbstractActor extends AbstractObject { private String name; - //IFI + // IFIs private String mbox; private String mbox_sha1sum; private String openid; private Account account; + // Getters and Setters public String getName() { return name; } @@ -51,4 +52,22 @@ public Account getAccount() { public void setAccount(Account account) { this.account = account; } + + // Validation + protected int countIFIs() { + int notNullCount = 0; + if (mbox != null) { + ++notNullCount; + } + if (mbox_sha1sum != null) { + ++notNullCount; + } + if (openid != null) { + ++notNullCount; + } + if (account != null) { + ++notNullCount; + } + return notNullCount; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Agent.java b/src/main/java/com/yetanalytics/xapi/model/Agent.java index 836186c..bf50df3 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Agent.java +++ b/src/main/java/com/yetanalytics/xapi/model/Agent.java @@ -13,4 +13,15 @@ @JsonDeserialize public class Agent extends AbstractActor { + // Validation + + /** + * Assertion that the Agent has only 1 Inverse Functional Identifier (IFI). + * @return true if the Agent has exactly 1 IFI, false otherwise + */ + @AssertTrue + public boolean isIdentifiedAgent() { + return countIFIs() == 1; + } + } diff --git a/src/test/java/com/yetanalytics/model/AgentTest.java b/src/test/java/com/yetanalytics/model/AgentTest.java new file mode 100644 index 0000000..97e6322 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/AgentTest.java @@ -0,0 +1,65 @@ +package com.yetanalytics.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Account; +import com.yetanalytics.xapi.model.Agent; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class AgentTest { + private Validator validator; + private Agent agent; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + agent = new Agent(); + } + + @Test + public void testMbox() { + agent.setMbox("mailto:foo@example.com"); + assertTrue(validator.validate(agent).isEmpty()); + } + + @Test + public void testMboxSha1Sum() { + agent.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); + assertTrue(validator.validate(agent).isEmpty()); + } + + @Test + public void testOpenid() { + agent.setOpenid("http://openid.example.com"); + assertTrue(validator.validate(agent).isEmpty()); + } + + @Test + public void testAccount() { + Account account = new Account(); + account.setHomePage("http://examplehomepage.com"); + account.setName("My Account"); + + agent.setAccount(account); + assertTrue(validator.validate(agent).isEmpty()); + } + + @Test + public void testNoIFI() { + var violations = validator.validate(agent); + assertEquals(1, violations.size()); + } + + @Test + public void testMultiIFI() { + agent.setMbox("mailto:foo@example.com"); + agent.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); + var violations = validator.validate(agent); + assertEquals(1, violations.size()); + } +} From 1e1553c37be6222ba406f9f6ddcf20817c325445 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:20:58 -0500 Subject: [PATCH 07/22] Add validation for anonymous vs identified groups --- .../com/yetanalytics/xapi/model/Group.java | 7 ++ .../com/yetanalytics/model/GroupTest.java | 80 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/test/java/com/yetanalytics/model/GroupTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Group.java b/src/main/java/com/yetanalytics/xapi/model/Group.java index 8ee8b8a..5ae74e1 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Group.java +++ b/src/main/java/com/yetanalytics/xapi/model/Group.java @@ -24,5 +24,12 @@ public void setMember(List member) { this.member = member; } + @AssertTrue + public boolean isAnonymousOrIdentifiedGroup() { + return ( + (countIFIs() == 0 && member != null) || + (countIFIs() == 1) + ); + } } diff --git a/src/test/java/com/yetanalytics/model/GroupTest.java b/src/test/java/com/yetanalytics/model/GroupTest.java new file mode 100644 index 0000000..dfd56ac --- /dev/null +++ b/src/test/java/com/yetanalytics/model/GroupTest.java @@ -0,0 +1,80 @@ +package com.yetanalytics.model; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Account; +import com.yetanalytics.xapi.model.Agent; +import com.yetanalytics.xapi.model.Group; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class GroupTest { + private Validator validator; + private Group group; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + group = new Group(); + } + + @Test + public void testAnomyousGroup() { + List member = new ArrayList<>(); + Agent memberAgent = new Agent(); + memberAgent.setMbox("mailto:mem@example.com"); + member.add(memberAgent); + group.setMember(member); + assertTrue(validator.validate(group).isEmpty()); + } + + @Test + public void testMbox() { + group.setMbox("mailto:foo@example.com"); + assertTrue(validator.validate(group).isEmpty()); + } + + @Test + public void testMboxSha1Sum() { + group.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); + assertTrue(validator.validate(group).isEmpty()); + } + + @Test + public void testOpenid() { + group.setOpenid("http://openid.example.com"); + assertTrue(validator.validate(group).isEmpty()); + } + + @Test + public void testAccount() { + Account account = new Account(); + account.setHomePage("http://examplehomepage.com"); + account.setName("My Account"); + + group.setAccount(account); + assertTrue(validator.validate(group).isEmpty()); + } + + @Test + public void testNoIFI() { // No member array => identified group + var violations = validator.validate(group); + assertEquals(1, violations.size()); + } + + @Test + public void testMultiIFI() { + group.setMbox("mailto:foo@example.com"); + group.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); + var violations = validator.validate(group); + assertEquals(1, violations.size()); + } + +} From dd6b67380642e7d84e1427e8d136a2c60def91e4 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:30:03 -0500 Subject: [PATCH 08/22] Add NotNull constraints to Account --- .../com/yetanalytics/xapi/model/Account.java | 5 ++- .../com/yetanalytics/model/AccountTest.java | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/yetanalytics/model/AccountTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Account.java b/src/main/java/com/yetanalytics/xapi/model/Account.java index 2f3469c..5470ad3 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Account.java +++ b/src/main/java/com/yetanalytics/xapi/model/Account.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.NotNull; + /** * Class representation of the Account Component of the * 9274.1.1 xAPI Specification. @@ -10,8 +12,9 @@ @JsonInclude(Include.NON_NULL) public class Account { + @NotNull private String homePage; - + @NotNull private String name; public String getHomePage() { diff --git a/src/test/java/com/yetanalytics/model/AccountTest.java b/src/test/java/com/yetanalytics/model/AccountTest.java new file mode 100644 index 0000000..845c077 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/AccountTest.java @@ -0,0 +1,36 @@ +package com.yetanalytics.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Account; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class AccountTest { + private Validator validator; + private Account account; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + account = new Account(); + } + + @Test + public void testValidAccount() { + account.setHomePage("http://examplehomepage.com"); + account.setName("My Account"); + assertTrue(validator.validate(account).isEmpty()); + } + + @Test + public void testEmptyAccount() { + var violations = validator.validate(account); + assertEquals(2, violations.size()); + } + +} From 1798221c11c74794e05013b2e60d19fbd707a622 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:35:01 -0500 Subject: [PATCH 09/22] Add tests and TODOs for actor fields --- .../java/com/yetanalytics/xapi/model/AbstractActor.java | 9 +++++++++ src/test/java/com/yetanalytics/model/AgentTest.java | 8 ++++++++ src/test/java/com/yetanalytics/model/GroupTest.java | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java index bc92abc..7e96a6b 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.AbstractActorDeserializer; +import jakarta.validation.Valid; + /** * Abstract Class for serialization and deserialization of xAPI Actors */ @@ -12,9 +14,14 @@ public abstract class AbstractActor extends AbstractObject { private String name; // IFIs + + // TODO: Validate mbox is a valid mailto IRI private String mbox; + // TODO: Validate mbox_sha1sum is a valid hash string private String mbox_sha1sum; + // TODO: Validate openid is a valid IRI private String openid; + @Valid private Account account; // Getters and Setters @@ -70,4 +77,6 @@ protected int countIFIs() { } return notNullCount; } + + public abstract boolean isValidAuthority(); } diff --git a/src/test/java/com/yetanalytics/model/AgentTest.java b/src/test/java/com/yetanalytics/model/AgentTest.java index 97e6322..eecf35a 100644 --- a/src/test/java/com/yetanalytics/model/AgentTest.java +++ b/src/test/java/com/yetanalytics/model/AgentTest.java @@ -49,6 +49,14 @@ public void testAccount() { assertTrue(validator.validate(agent).isEmpty()); } + @Test + public void testInvalidAccount() { + Account account = new Account(); + agent.setAccount(account); + var violations = validator.validate(agent); + assertEquals(2, violations.size()); + } + @Test public void testNoIFI() { var violations = validator.validate(agent); diff --git a/src/test/java/com/yetanalytics/model/GroupTest.java b/src/test/java/com/yetanalytics/model/GroupTest.java index dfd56ac..8ebbce8 100644 --- a/src/test/java/com/yetanalytics/model/GroupTest.java +++ b/src/test/java/com/yetanalytics/model/GroupTest.java @@ -63,6 +63,14 @@ public void testAccount() { assertTrue(validator.validate(group).isEmpty()); } + @Test + public void testInvalidAccount() { + Account account = new Account(); + group.setAccount(account); + var violations = validator.validate(group); + assertEquals(2, violations.size()); + } + @Test public void testNoIFI() { // No member array => identified group var violations = validator.validate(group); From 6314acdd5fa3b9f3afc2445d0ccf549c3b9d2e26 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:35:55 -0500 Subject: [PATCH 10/22] Don't forget imports in Agent and Group classes --- src/main/java/com/yetanalytics/xapi/model/Agent.java | 4 +++- src/main/java/com/yetanalytics/xapi/model/Group.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/yetanalytics/xapi/model/Agent.java b/src/main/java/com/yetanalytics/xapi/model/Agent.java index bf50df3..cc9e8d0 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Agent.java +++ b/src/main/java/com/yetanalytics/xapi/model/Agent.java @@ -1,8 +1,10 @@ package com.yetanalytics.xapi.model; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import jakarta.validation.constraints.AssertTrue; /** * A concrete class representation of the Agent Component of the diff --git a/src/main/java/com/yetanalytics/xapi/model/Group.java b/src/main/java/com/yetanalytics/xapi/model/Group.java index 5ae74e1..cc05c29 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Group.java +++ b/src/main/java/com/yetanalytics/xapi/model/Group.java @@ -2,9 +2,11 @@ import java.util.List; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import jakarta.validation.constraints.AssertTrue; /** * Class representation of the Group Component of the From 8191807caea9f37f6055824ab0f05974146f9ee0 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 5 Dec 2024 16:50:16 -0500 Subject: [PATCH 11/22] Add Verb validation --- .../com/yetanalytics/xapi/model/Verb.java | 15 +++++-- .../java/com/yetanalytics/model/VerbTest.java | 41 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/yetanalytics/model/VerbTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Verb.java b/src/main/java/com/yetanalytics/xapi/model/Verb.java index b00c5b7..e6d1178 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Verb.java +++ b/src/main/java/com/yetanalytics/xapi/model/Verb.java @@ -1,9 +1,11 @@ package com.yetanalytics.xapi.model; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.yetanalytics.xapi.model.deserializers.LangMapDeserializer; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.yetanalytics.xapi.model.deserializers.LangMapDeserializer; + +import jakarta.validation.constraints.NotNull; /** * Class representation of the Verb component of the @@ -12,7 +14,10 @@ @JsonInclude(Include.NON_NULL) public class Verb { - private String id; + public static final String VOIDING_VERB_IRI = "http://adlnet.gov/expapi/verbs/voided"; + + @NotNull + private String id; // TODO: Validate id is an IRI @JsonDeserialize(using = LangMapDeserializer.class) private LangMap display; @@ -32,5 +37,9 @@ public LangMap getDisplay() { public void setDisplay(LangMap display) { this.display = display; } + + public boolean isVoiding() { + return id == VOIDING_VERB_IRI; + } } diff --git a/src/test/java/com/yetanalytics/model/VerbTest.java b/src/test/java/com/yetanalytics/model/VerbTest.java new file mode 100644 index 0000000..7bac522 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/VerbTest.java @@ -0,0 +1,41 @@ +package com.yetanalytics.model; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.LangMap; +import com.yetanalytics.xapi.model.Verb; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class VerbTest { + private Validator validator; + private Verb verb; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + verb = new Verb(); + } + + @Test + public void testVerb() { + LangMap display = new LangMap(new HashMap<>()); + display.put("en-US", "Example Verb"); + + verb.setId("http://example.com/verb"); + verb.setDisplay(display); + assertTrue(validator.validate(verb).isEmpty()); + } + + @Test + public void testEmptyVerb() { + var violations = validator.validate(verb); + assertEquals(1, violations.size()); + } +} From f8e7427432bca48b7baaebfd73d56636bc83589a Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 13:29:48 -0500 Subject: [PATCH 12/22] Add Activity + ActivityDefinition validation --- .../com/yetanalytics/xapi/model/Activity.java | 7 +- .../xapi/model/ActivityDefinition.java | 81 +++++++++ .../model/ActivityDefinitionTest.java | 156 ++++++++++++++++++ .../com/yetanalytics/model/ActivityTest.java | 42 +++++ 4 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java create mode 100644 src/test/java/com/yetanalytics/model/ActivityTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Activity.java b/src/main/java/com/yetanalytics/xapi/model/Activity.java index 91fa6fd..b730b25 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Activity.java +++ b/src/main/java/com/yetanalytics/xapi/model/Activity.java @@ -1,8 +1,11 @@ package com.yetanalytics.xapi.model; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * Class representation of the Activity Object Type of the @@ -11,8 +14,10 @@ @JsonInclude(Include.NON_NULL) @JsonDeserialize public class Activity extends AbstractObject { + @NotNull private String id; + @Valid private ActivityDefinition definition; public String getId() { diff --git a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java index 853c7be..b83e473 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java +++ b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertTrue; + /** * Class representation of the Activity Definition Component of the * 9274.1.1 xAPI Specification. @@ -101,4 +103,83 @@ public List getSteps() { public void setSteps(List steps) { this.steps = steps; } + + // Validation + + private boolean isChoices() { + return ( + // choices is allowed + scale == null && + source == null && + target == null && + steps == null + ); + } + + private boolean isScale() { + return ( + // scale is allowed + choices == null && + source == null && + target == null && + steps == null + ); + } + + private boolean isSourceTarget() { + return ( + // source and target are allowed + choices == null && + scale == null && + steps == null + ); + } + + private boolean isSteps() { + return ( + // steps is allowed + choices == null && + scale == null && + source == null && + target == null + ); + } + + private boolean isNoInteractionComponents() { + return ( + choices == null && + scale == null && + source == null && + target == null && + steps == null + ); + } + + private boolean isNoInteraction() { + return ( + isNoInteractionComponents() && + correctResponsesPattern == null + ); + } + + @AssertTrue + public boolean isValidInteractionActivity() { + if (interactionType == null) { + return isNoInteraction(); + } + switch (interactionType) { + case CHOICE: + return isChoices(); + case SEQUENCING: + return isChoices(); + case LIKERT: + return isScale(); + case MATCHING: + return isSourceTarget(); + case PERFORMANCE: + return isSteps(); + default: + return isNoInteractionComponents(); + } + } } diff --git a/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java new file mode 100644 index 0000000..164e194 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java @@ -0,0 +1,156 @@ +package com.yetanalytics.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.ActivityDefinition; +import com.yetanalytics.xapi.model.Extensions; +import com.yetanalytics.xapi.model.InteractionComponent; +import com.yetanalytics.xapi.model.InteractionType; +import com.yetanalytics.xapi.model.LangMap; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class ActivityDefinitionTest { + private Validator validator; + private ActivityDefinition definition; + + private List makeComp(String id, String descStr) { + LangMap desc = new LangMap(new HashMap<>()); + desc.put("en-US", descStr); + + InteractionComponent component = new InteractionComponent(); + component.setId(id); + component.setDescription(desc); + + List components = new ArrayList<>(); + components.add(component); + + return components; + } + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + definition = new ActivityDefinition(); + } + + @Test + public void testEmptyDefinition() { + assertTrue(validator.validate(definition).isEmpty()); + } + + @Test + public void testDefinition() { + LangMap name = new LangMap(new HashMap<>()); + name.put("en-US", "Example Definition"); + + LangMap desc = new LangMap(new HashMap<>()); + desc.put("en-US", "This is an example Activity Definition"); + + String type = "http://example.com/activity-type"; + + String moreInfo = "http://yetanalytics.com"; + + Extensions ext = new Extensions(new HashMap<>()); + ext.put("http://example.org/string-value", "Foo Bar"); + + definition.setName(name); + definition.setDescription(desc); + definition.setType(type); + definition.setMoreInfo(moreInfo); + definition.setExtensions(ext); + + assertTrue(validator.validate(definition).isEmpty()); + + List choices = makeComp("component", "Interaction Component"); + definition.setChoices(choices); + + List correctResponsesPattern = new ArrayList<>(); + correctResponsesPattern.add("Response 1"); + correctResponsesPattern.add("Response 2"); + definition.setCorrectResponsesPattern(correctResponsesPattern); + + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } + + @Test + public void testChoiceDefinition() { + definition.setInteractionType(InteractionType.CHOICE); + assertTrue(validator.validate(definition).isEmpty()); + + List choices = makeComp("choice", "Choice"); + definition.setChoices(choices); + assertTrue(validator.validate(definition).isEmpty()); + + definition.setInteractionType(InteractionType.TRUE_FALSE); + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } + + @Test + public void testSequencingDefinition() { + definition.setInteractionType(InteractionType.SEQUENCING); + assertTrue(validator.validate(definition).isEmpty()); + + List choices = makeComp("choice", "Choice"); + definition.setChoices(choices); + assertTrue(validator.validate(definition).isEmpty()); + + definition.setInteractionType(InteractionType.FILL_IN); + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } + + @Test + public void testLikertDefinition() { + definition.setInteractionType(InteractionType.LIKERT); + assertTrue(validator.validate(definition).isEmpty()); + + List scale = makeComp("scale", "Scale"); + definition.setScale(scale); + assertTrue(validator.validate(definition).isEmpty()); + + definition.setInteractionType(InteractionType.LONG_FILL_IN); + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } + + @Test + public void testMatchingDefinition() { + definition.setInteractionType(InteractionType.MATCHING); + assertTrue(validator.validate(definition).isEmpty()); + + List source = makeComp("source", "Source"); + List target = makeComp("target", "Target"); + definition.setSource(source); + definition.setTarget(target); + assertTrue(validator.validate(definition).isEmpty()); + + definition.setInteractionType(InteractionType.NUMERIC); + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } + + @Test + public void testPerformanceDefinition() { + definition.setInteractionType(InteractionType.PERFORMANCE); + assertTrue(validator.validate(definition).isEmpty()); + + List steps = makeComp("steps", "Steps"); + definition.setSteps(steps); + assertTrue(validator.validate(definition).isEmpty()); + + definition.setInteractionType(InteractionType.OTHER); + var violations = validator.validate(definition); + assertEquals(1, violations.size()); + } +} diff --git a/src/test/java/com/yetanalytics/model/ActivityTest.java b/src/test/java/com/yetanalytics/model/ActivityTest.java new file mode 100644 index 0000000..dcf96a3 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/ActivityTest.java @@ -0,0 +1,42 @@ +package com.yetanalytics.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Activity; +import com.yetanalytics.xapi.model.ActivityDefinition; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class ActivityTest { + private Validator validator; + private ActivityDefinition definition; + private Activity activity; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + definition = new ActivityDefinition(); + activity = new Activity(); + } + + @Test + public void testActivity() { + activity.setId("http://example.org/activity"); + assertTrue(validator.validate(activity).isEmpty()); + + // TODO: Enforce that definitions, as JSON objects, can't be empty + // For now we allow them though + activity.setDefinition(definition); + assertTrue(validator.validate(activity).isEmpty()); + } + + @Test + public void testEmptyActivity() { + var violations = validator.validate(activity); + assertEquals(1, violations.size()); + } +} From 2bc3d50006e55d460e67d7b2629427be6eba318f Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 13:47:06 -0500 Subject: [PATCH 13/22] Add Result and Score --- .../com/yetanalytics/xapi/model/Result.java | 3 + .../com/yetanalytics/xapi/model/Score.java | 37 ++++++++++ .../com/yetanalytics/model/ResultTest.java | 48 ++++++++++++ .../com/yetanalytics/model/ScoreTest.java | 73 +++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 src/test/java/com/yetanalytics/model/ResultTest.java create mode 100644 src/test/java/com/yetanalytics/model/ScoreTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Result.java b/src/main/java/com/yetanalytics/xapi/model/Result.java index bc69724..b4e47db 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Result.java +++ b/src/main/java/com/yetanalytics/xapi/model/Result.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.Valid; + /** * Class representation of the Result component of the * 9274.1.1 xAPI Specification. @@ -10,6 +12,7 @@ @JsonInclude(Include.NON_NULL) public class Result { + @Valid private Score score; private Boolean success; private Boolean completion; diff --git a/src/main/java/com/yetanalytics/xapi/model/Score.java b/src/main/java/com/yetanalytics/xapi/model/Score.java index d7a6225..1388a56 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Score.java +++ b/src/main/java/com/yetanalytics/xapi/model/Score.java @@ -1,9 +1,14 @@ package com.yetanalytics.xapi.model; + import java.math.BigDecimal; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; + /** * Class representation of the Score component of the * 9274.1.1 xAPI Specification. @@ -14,6 +19,9 @@ public class Score { private BigDecimal raw; private BigDecimal min; private BigDecimal max; + + @DecimalMax(value = "1.0") + @DecimalMin(value = "-1.0") private BigDecimal scaled; public BigDecimal getRaw() { @@ -40,4 +48,33 @@ public BigDecimal getScaled() { public void setScaled(BigDecimal scaled) { this.scaled = scaled; } + + // Validation + + @AssertTrue + public boolean isMinLessThanRaw() { + if (raw != null && min != null) { + return min.compareTo(raw) < 0; + } else { + return true; + } + } + + @AssertTrue + public boolean isRawLessThanMax() { + if (raw != null && max != null) { + return raw.compareTo(max) < 0; + } else { + return true; + } + } + + @AssertTrue + public boolean isMinLessThanMax() { + if (min != null && max != null) { + return min.compareTo(max) < 0; + } else { + return true; + } + } } diff --git a/src/test/java/com/yetanalytics/model/ResultTest.java b/src/test/java/com/yetanalytics/model/ResultTest.java new file mode 100644 index 0000000..c5f0c94 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/ResultTest.java @@ -0,0 +1,48 @@ +package com.yetanalytics.model; + +import java.math.BigDecimal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Result; +import com.yetanalytics.xapi.model.Score; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class ResultTest { + private Validator validator; + private Result result; + private Score score; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + score = new Score(); + result = new Result(); + } + + @Test + public void testResult() { + score.setScaled(new BigDecimal(0.5)); + result.setScore(score); + result.setSuccess(false); + result.setCompletion(true); + result.setResponse("myResponse"); + // TODO: setExtensions + // TODO: setDuration + + assertTrue(validator.validate(result).isEmpty()); + } + + @Test + public void testInvalidScore() { + score.setScaled(new BigDecimal(3.0)); + result.setScore(score); + assertEquals(1, validator.validate(result).size()); + } + +} diff --git a/src/test/java/com/yetanalytics/model/ScoreTest.java b/src/test/java/com/yetanalytics/model/ScoreTest.java new file mode 100644 index 0000000..66c85f1 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/ScoreTest.java @@ -0,0 +1,73 @@ +package com.yetanalytics.model; + +import java.math.BigDecimal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Score; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class ScoreTest { + private Validator validator; + private Score score; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + score = new Score(); + } + + @Test + public void testScore() { + assertTrue(validator.validate(score).isEmpty()); + + score.setMin(new BigDecimal(0)); + score.setMax(new BigDecimal(100)); + score.setRaw(new BigDecimal(50)); + score.setScaled(new BigDecimal(0)); + assertTrue(validator.validate(score).isEmpty()); + } + + @Test + public void testScaledTooSmall() { + score.setScaled(new BigDecimal(-2.0)); + var violations = validator.validate(score); + assertEquals(1, violations.size()); + } + + @Test + public void testScaledTooBig() { + score.setScaled(new BigDecimal(2.0)); + var violations = validator.validate(score); + assertEquals(1, violations.size()); + } + + @Test + public void testMinBiggerThanMax() { + score.setMax(new BigDecimal(0.4)); + score.setMin(new BigDecimal(0.6)); + var violations = validator.validate(score); + assertEquals(1, violations.size()); + } + + @Test + public void testRawBiggerThanMax() { + score.setMax(new BigDecimal(0.4)); + score.setRaw(new BigDecimal(0.6)); + var violations = validator.validate(score); + assertEquals(1, violations.size()); + } + + @Test + public void testMinBiggerThanRaw() { + score.setRaw(new BigDecimal(0.4)); + score.setMin(new BigDecimal(0.6)); + var violations = validator.validate(score); + assertEquals(1, violations.size()); + } +} From 7e54c630270262418c5c18bd832c91a62a620e17 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 13:51:48 -0500 Subject: [PATCH 14/22] Add InteractionComponent --- .../xapi/model/InteractionComponent.java | 3 ++ .../model/InteractionComponentTest.java | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/java/com/yetanalytics/model/InteractionComponentTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java index bc40fed..0966dc4 100644 --- a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java +++ b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.NotNull; + /** * Class representation of the Interaction Component of the * 9274.1.1 xAPI Specification. @@ -9,6 +11,7 @@ @JsonInclude(Include.NON_NULL) public class InteractionComponent { + @NotNull private String id; private LangMap description; diff --git a/src/test/java/com/yetanalytics/model/InteractionComponentTest.java b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java new file mode 100644 index 0000000..8149fed --- /dev/null +++ b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java @@ -0,0 +1,39 @@ +package com.yetanalytics.model; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.InteractionComponent; +import com.yetanalytics.xapi.model.LangMap; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class InteractionComponentTest { + private Validator validator; + private InteractionComponent interactionComponent; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + interactionComponent = new InteractionComponent(); + } + + @Test + public void testInteractionComponent() { + LangMap desc = new LangMap(new HashMap<>()); + desc.put("en-US", "Foo"); + interactionComponent.setId("foo"); + interactionComponent.setDescription(desc); + assertTrue(validator.validate(interactionComponent).isEmpty()); + } + + @Test + public void testEmpytInteractionComponent() { + assertEquals(1, validator.validate(interactionComponent).size()); + } +} From 94725e4f703613518e372d9daa2b176f4e67d200 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 14:10:54 -0500 Subject: [PATCH 15/22] Add Attachment constraints --- .../yetanalytics/xapi/model/Attachment.java | 7 +++ .../yetanalytics/model/AttachmentTest.java | 53 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/test/java/com/yetanalytics/model/AttachmentTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Attachment.java b/src/main/java/com/yetanalytics/xapi/model/Attachment.java index 69faca2..149f05a 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Attachment.java +++ b/src/main/java/com/yetanalytics/xapi/model/Attachment.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.NotNull; + /** * Class representation of the Attachment Component of the * 9274.1.1 xAPI Specification. @@ -10,11 +12,16 @@ @JsonInclude(Include.NON_NULL) public class Attachment { + @NotNull private String usageType; + @NotNull private LangMap display; private LangMap description; + @NotNull private String contentType; + @NotNull private Integer length; + @NotNull private String sha2; private String fileUrl; diff --git a/src/test/java/com/yetanalytics/model/AttachmentTest.java b/src/test/java/com/yetanalytics/model/AttachmentTest.java new file mode 100644 index 0000000..c82f40b --- /dev/null +++ b/src/test/java/com/yetanalytics/model/AttachmentTest.java @@ -0,0 +1,53 @@ +package com.yetanalytics.model; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Attachment; +import com.yetanalytics.xapi.model.LangMap; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class AttachmentTest { + private Validator validator; + private Attachment attachment; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + attachment = new Attachment(); + } + + @Test + public void testAttachment() { + LangMap display = new LangMap(new HashMap<>()); + display.put("en-US", "Display"); + + LangMap desc = new LangMap(new HashMap<>()); + desc.put("en-US", "Description"); + + String contentType = "application/json"; + int length = 450; + String sha2 = "426cf3a8b2864dd91201b989ba5728181da52bfff9a0489670e54cd8ec8b3a50"; + String fileUrl = "https://www.yetanalytics.com/files/file1.json"; + + attachment.setUsageType("http://example.com/attachment"); + attachment.setDisplay(display); + attachment.setDescription(desc); + attachment.setContentType(contentType); + attachment.setLength(length); + attachment.setSha2(sha2); + attachment.setFileUrl(fileUrl); + assertTrue(validator.validate(attachment).isEmpty()); + } + + @Test + public void testEmptyAttachment() { + assertEquals(5, validator.validate(attachment).size()); + } +} From 1007b0731ea45314ff2ed2da5b092e03ac4ad60b Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 14:18:54 -0500 Subject: [PATCH 16/22] Add StatementRef constraints --- .../yetanalytics/xapi/model/StatementRef.java | 5 ++- .../yetanalytics/model/StatementRefTest.java | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/yetanalytics/model/StatementRefTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java index 2a4e19e..477a7f5 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java @@ -2,9 +2,11 @@ import java.util.UUID; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import jakarta.validation.constraints.NotNull; /** * Class representation of the StatementRef component of the @@ -13,6 +15,7 @@ @JsonInclude(Include.NON_NULL) @JsonDeserialize public class StatementRef extends AbstractObject { + @NotNull private UUID id; public UUID getId() { diff --git a/src/test/java/com/yetanalytics/model/StatementRefTest.java b/src/test/java/com/yetanalytics/model/StatementRefTest.java new file mode 100644 index 0000000..4584ae7 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/StatementRefTest.java @@ -0,0 +1,37 @@ +package com.yetanalytics.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.StatementRef; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class StatementRefTest { + private Validator validator; + private StatementRef statementRef; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + statementRef = new StatementRef(); + } + + @Test + public void testStatementRef() { + String id = "00000000-4000-8000-0000-000000000000"; + statementRef.setId(UUID.fromString(id)); + assertTrue(validator.validate(statementRef).isEmpty()); + } + + @Test + public void testEmptyStatementRef() { + assertEquals(1, validator.validate(statementRef).size()); + } +} From 72445b6f141df2a471055afb24e2f378a55408b8 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 15:22:32 -0500 Subject: [PATCH 17/22] Implement constraints for Statements (incl Authority checks) --- .../com/yetanalytics/xapi/model/Agent.java | 4 + .../com/yetanalytics/xapi/model/Group.java | 14 ++ .../yetanalytics/xapi/model/Statement.java | 81 +++++++- .../com/yetanalytics/model/StatementTest.java | 192 ++++++++++++++++++ 4 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/yetanalytics/model/StatementTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/Agent.java b/src/main/java/com/yetanalytics/xapi/model/Agent.java index cc9e8d0..a234efb 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Agent.java +++ b/src/main/java/com/yetanalytics/xapi/model/Agent.java @@ -26,4 +26,8 @@ public boolean isIdentifiedAgent() { return countIFIs() == 1; } + @Override + public boolean isValidAuthority() { + return true; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Group.java b/src/main/java/com/yetanalytics/xapi/model/Group.java index cc05c29..333476e 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Group.java +++ b/src/main/java/com/yetanalytics/xapi/model/Group.java @@ -34,4 +34,18 @@ public boolean isAnonymousOrIdentifiedGroup() { ); } + private boolean isValidConsumer(Agent consumer) { + return consumer.getAccount() != null; + } + + @Override + public boolean isValidAuthority() { + return ( + member.size() == 2 && + ( + isValidConsumer(member.get(0)) || + isValidConsumer(member.get(1)) + ) + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Statement.java b/src/main/java/com/yetanalytics/xapi/model/Statement.java index 965d9f5..7031777 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Statement.java +++ b/src/main/java/com/yetanalytics/xapi/model/Statement.java @@ -1,15 +1,18 @@ package com.yetanalytics.xapi.model; +import java.time.ZonedDateTime; import java.util.List; import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.yetanalytics.xapi.model.serializers.DateTimeSerializer; -import java.time.ZonedDateTime; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; /** * Class representation of an Statement from the 9274.1.1 xAPI Specification. @@ -20,16 +23,25 @@ public class Statement extends AbstractObject { private UUID id; + @NotNull + @Valid private AbstractObject actor; + @NotNull + @Valid private Verb verb; + @Valid private Result result; + @Valid private Context context; + @NotNull + @Valid private AbstractObject object; + @Valid private AbstractActor authority; @JsonSerialize(using = DateTimeSerializer.class) @@ -129,4 +141,67 @@ public List getAttachments() { public void setAttachments(List attachments) { this.attachments = attachments; } + + // Validation + + @AssertTrue + public boolean isValidVoidingStatement() { + if (verb != null && verb.isVoiding()) { + return object instanceof StatementRef; + } else { + return true; + } + } + + private boolean isObjectActivity() { + if (object != null) { + return object instanceof Activity; + } else { + return false; // Invalid statement anyways + } + } + + @AssertTrue + public boolean isValidContextRevision() { + return ( + isObjectActivity() || + context == null || + context.getRevision() == null + ); + } + + @AssertTrue + public boolean isValidContextPlatform() { + return ( + isObjectActivity() || + context == null || + context.getPlatform() == null + ); + } + + // TODO: Somehow validate this on the Authority object itself + @AssertTrue + public boolean isValidAuthority() { + return authority == null || authority.isValidAuthority(); + } + + // TODO: Validate this on the SubStatement itself + // (e.g. setting the objectType field) + @AssertTrue + public boolean isValidSubStatement() { + // System.out.println("Object is Statement: " + (object instanceof Statement)); + // TODO: If object is true... + if (object instanceof Statement) { + Statement subStatement = (Statement) object; + return ( + subStatement.getId() == null && + subStatement.getStored() == null && + subStatement.getVersion() == null && + subStatement.getAuthority() == null && + !(subStatement.getObject() instanceof Statement) + ); + } else { + return true; + } + } } diff --git a/src/test/java/com/yetanalytics/model/StatementTest.java b/src/test/java/com/yetanalytics/model/StatementTest.java new file mode 100644 index 0000000..780d101 --- /dev/null +++ b/src/test/java/com/yetanalytics/model/StatementTest.java @@ -0,0 +1,192 @@ +package com.yetanalytics.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Account; +import com.yetanalytics.xapi.model.Activity; +import com.yetanalytics.xapi.model.Agent; +import com.yetanalytics.xapi.model.Context; +import com.yetanalytics.xapi.model.Group; +import com.yetanalytics.xapi.model.Statement; +import com.yetanalytics.xapi.model.StatementRef; +import com.yetanalytics.xapi.model.Verb; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class StatementTest { + private Validator validator; + private Statement statement; + + private StatementRef genericStatementRef() { + UUID id = UUID.fromString("00000000-4000-8000-0000-000000000000"); + StatementRef statementRef = new StatementRef(); + statementRef.setId(id); + return statementRef; + } + + @Before + public void initStatement() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + statement = new Statement(); + + // Valid statement by default + Agent actor = new Agent(); + actor.setMbox("mailto:foo@example.com"); + + Verb verb = new Verb(); + verb.setId("http://example.org/verb"); + + Activity object = new Activity(); + object.setId("http://example.org/object"); + + statement.setActor(actor); + statement.setVerb(verb); + statement.setObject(object); + } + + @Test + public void testStatement() { + assertTrue(validator.validate(statement).isEmpty()); + } + + @Test + public void testEmptyStatement() { + statement.setActor(null); + statement.setVerb(null); + statement.setObject(null); + assertEquals(3, validator.validate(statement).size()); + } + + @Test + public void testVoidingStatement() { + Verb voidingVerb = new Verb(); + voidingVerb.setId(Verb.VOIDING_VERB_IRI); + + statement.setVerb(voidingVerb); + assertEquals(1, validator.validate(statement).size()); + + StatementRef statementRef = genericStatementRef(); + statement.setObject(statementRef); + + assertTrue(validator.validate(statement).isEmpty()); + } + + @Test + public void testValidContextRevision() { + Context context = new Context(); + context.setRevision("myRevision"); + statement.setContext(context); + assertTrue(validator.validate(statement).isEmpty()); + + StatementRef statementRef = genericStatementRef(); + statement.setObject(statementRef); + + assertEquals(1, validator.validate(statement).size()); + } + + @Test + public void testValidContextPlatform() { + Context context = new Context(); + context.setRevision("myPlatform"); + statement.setContext(context); + assertTrue(validator.validate(statement).isEmpty()); + + StatementRef statementRef = genericStatementRef(); + statement.setObject(statementRef); + + assertEquals(1, validator.validate(statement).size()); + } + + @Test + public void testValidAuthority() { + Account authAccount = new Account(); + authAccount.setHomePage("http://myauthority.com"); + authAccount.setName("My Authority"); + + // Agent authority is always valid + Agent agentAuthority = new Agent(); + agentAuthority.setAccount(authAccount); + statement.setAuthority(agentAuthority); + assertTrue(validator.validate(statement).isEmpty()); + + // Group authority fails if there is not two members + Group groupAuthority = new Group(); + List groupAuthMember = new ArrayList<>(); + groupAuthMember.add(agentAuthority); + groupAuthority.setMember(groupAuthMember); + statement.setAuthority(groupAuthority); + assertEquals(1, validator.validate(statement).size()); + + // Need to add second member + Agent nonConsumer = new Agent(); + nonConsumer.setMbox("mailto:someagent@example.com"); + groupAuthMember.add(nonConsumer); + assertTrue(validator.validate(statement).isEmpty()); + + // At least one member needs to have an Account + groupAuthMember.set(0, nonConsumer); + assertEquals(1, validator.validate(statement).size()); + + // Cannot have three (or more) members + groupAuthMember.set(0, agentAuthority); + groupAuthMember.add(nonConsumer); + assertEquals(1, validator.validate(statement).size()); + } + + @Test + public void testValidSubStatement() { + Statement subStatement = new Statement(); + Agent actor = new Agent(); + actor.setMbox("mailto:bar@example.com"); + Verb verb = new Verb(); + verb.setId("http://example.org/verb2"); + Activity object = new Activity(); + object.setId("http://example.org/object2"); + subStatement.setActor(actor); + subStatement.setVerb(verb); + subStatement.setObject(object); + statement.setObject(subStatement); + assertTrue(statement.getObject() instanceof Statement); + assertTrue(validator.validate(statement).isEmpty()); + + UUID id = UUID.fromString("00000000-4000-8000-0000-000000000000"); + subStatement.setId(id); + assertEquals(1, validator.validate(statement).size()); + + // TODO: test Stored presence + + String version = "1.0.3"; + subStatement.setId(null); + subStatement.setVersion(version); + assertEquals(1, validator.validate(statement).size()); + + Agent authority = new Agent(); + authority.setMbox("mailto:myauthority@example.com"); + subStatement.setVersion(null); + subStatement.setAuthority(authority); + assertEquals(1, validator.validate(statement).size()); + + Statement subSubStatement = new Statement(); + Agent actor2 = new Agent(); + actor2.setMbox("mailto:baz@example.com"); + Verb verb2 = new Verb(); + verb2.setId("http://example.org/verb3"); + Activity object2 = new Activity(); + object2.setId("http://example.org/object3"); + subSubStatement.setActor(actor); + subSubStatement.setVerb(verb); + subSubStatement.setObject(object); + subStatement.setAuthority(null); + subStatement.setObject(subStatement); + // TODO: Dig deeper why this is 2 errors and not 1 + assertEquals(2, validator.validate(statement).size()); + } +} From 9074e731d203852781a96c2ef29488197410ad07 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Fri, 6 Dec 2024 15:24:25 -0500 Subject: [PATCH 18/22] Add StatementResult --- .../xapi/model/StatementResult.java | 3 + .../model/StatementResultTest.java | 57 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/test/java/com/yetanalytics/model/StatementResultTest.java diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java index b77ac05..6272807 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java @@ -5,12 +5,15 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.NotNull; + /** * Class representation of a StatementResult from the 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) public class StatementResult { + @NotNull private List statements; private String more; diff --git a/src/test/java/com/yetanalytics/model/StatementResultTest.java b/src/test/java/com/yetanalytics/model/StatementResultTest.java new file mode 100644 index 0000000..b9a9d0f --- /dev/null +++ b/src/test/java/com/yetanalytics/model/StatementResultTest.java @@ -0,0 +1,57 @@ +package com.yetanalytics.model; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import com.yetanalytics.xapi.model.Activity; +import com.yetanalytics.xapi.model.Agent; +import com.yetanalytics.xapi.model.Statement; +import com.yetanalytics.xapi.model.StatementResult; +import com.yetanalytics.xapi.model.Verb; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class StatementResultTest { + private Validator validator; + private StatementResult statementResult; + + @Before + public void initValidator() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + statementResult = new StatementResult(); + } + + @Test + public void testStatementResult() { + Agent actor = new Agent(); + actor.setMbox("mailto:foo@example.com"); + + Verb verb = new Verb(); + verb.setId("http://example.org/verb"); + + Activity object = new Activity(); + object.setId("http://example.org/object"); + + Statement statement = new Statement(); + statement.setActor(actor); + statement.setVerb(verb); + statement.setObject(object); + + List statements = new ArrayList<>(); + statements.add(statement); + statementResult.setStatements(statements); + + assertTrue(validator.validate(statements).isEmpty()); + } + + @Test + public void testEmptyStatementResult() { + assertEquals(1, validator.validate(statementResult).size()); + } +} From 91d5ccd9828841d50e5ae27cf45c2ae7e1560f5f Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Mon, 9 Dec 2024 10:18:55 -0500 Subject: [PATCH 19/22] Add ValidationUtils class with custom asserts --- .../com/yetanalytics/model/AccountTest.java | 14 ++---- .../model/ActivityDefinitionTest.java | 48 ++++++++----------- .../com/yetanalytics/model/ActivityTest.java | 15 +++--- .../com/yetanalytics/model/AgentTest.java | 25 ++++------ .../yetanalytics/model/AttachmentTest.java | 13 +++-- .../com/yetanalytics/model/GroupTest.java | 28 +++++------ .../model/InteractionComponentTest.java | 12 ++--- .../com/yetanalytics/model/ResultTest.java | 13 ++--- .../com/yetanalytics/model/ScoreTest.java | 27 ++++------- .../yetanalytics/model/StatementRefTest.java | 13 ++--- .../model/StatementResultTest.java | 12 ++--- .../com/yetanalytics/model/StatementTest.java | 34 ++++++------- .../java/com/yetanalytics/model/VerbTest.java | 13 ++--- .../yetanalytics/util/ValidationUtils.java | 26 ++++++++++ 14 files changed, 137 insertions(+), 156 deletions(-) create mode 100644 src/test/java/com/yetanalytics/util/ValidationUtils.java diff --git a/src/test/java/com/yetanalytics/model/AccountTest.java b/src/test/java/com/yetanalytics/model/AccountTest.java index 845c077..fa54cb3 100644 --- a/src/test/java/com/yetanalytics/model/AccountTest.java +++ b/src/test/java/com/yetanalytics/model/AccountTest.java @@ -1,13 +1,11 @@ package com.yetanalytics.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Account; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class AccountTest { @@ -15,8 +13,8 @@ public class AccountTest { private Account account; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); account = new Account(); } @@ -24,13 +22,11 @@ public void initValidator() { public void testValidAccount() { account.setHomePage("http://examplehomepage.com"); account.setName("My Account"); - assertTrue(validator.validate(account).isEmpty()); + ValidationUtils.assertValid(validator, account); } @Test public void testEmptyAccount() { - var violations = validator.validate(account); - assertEquals(2, violations.size()); + ValidationUtils.assertInvalid(validator, account, 2); } - } diff --git a/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java index 164e194..19ab497 100644 --- a/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java +++ b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java @@ -4,18 +4,17 @@ import java.util.HashMap; import java.util.List; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.ActivityDefinition; import com.yetanalytics.xapi.model.Extensions; import com.yetanalytics.xapi.model.InteractionComponent; import com.yetanalytics.xapi.model.InteractionType; import com.yetanalytics.xapi.model.LangMap; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class ActivityDefinitionTest { @@ -37,14 +36,14 @@ private List makeComp(String id, String descStr) { } @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); definition = new ActivityDefinition(); } @Test public void testEmptyDefinition() { - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); } @Test @@ -68,6 +67,7 @@ public void testDefinition() { definition.setMoreInfo(moreInfo); definition.setExtensions(ext); + ValidationUtils.assertValid(validator, definition); assertTrue(validator.validate(definition).isEmpty()); List choices = makeComp("component", "Interaction Component"); @@ -78,79 +78,73 @@ public void testDefinition() { correctResponsesPattern.add("Response 2"); definition.setCorrectResponsesPattern(correctResponsesPattern); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } @Test public void testChoiceDefinition() { definition.setInteractionType(InteractionType.CHOICE); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); List choices = makeComp("choice", "Choice"); definition.setChoices(choices); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); definition.setInteractionType(InteractionType.TRUE_FALSE); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } @Test public void testSequencingDefinition() { definition.setInteractionType(InteractionType.SEQUENCING); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); List choices = makeComp("choice", "Choice"); definition.setChoices(choices); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); definition.setInteractionType(InteractionType.FILL_IN); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } @Test public void testLikertDefinition() { definition.setInteractionType(InteractionType.LIKERT); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); List scale = makeComp("scale", "Scale"); definition.setScale(scale); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); definition.setInteractionType(InteractionType.LONG_FILL_IN); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } @Test public void testMatchingDefinition() { definition.setInteractionType(InteractionType.MATCHING); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); List source = makeComp("source", "Source"); List target = makeComp("target", "Target"); definition.setSource(source); definition.setTarget(target); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); definition.setInteractionType(InteractionType.NUMERIC); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } @Test public void testPerformanceDefinition() { definition.setInteractionType(InteractionType.PERFORMANCE); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); List steps = makeComp("steps", "Steps"); definition.setSteps(steps); - assertTrue(validator.validate(definition).isEmpty()); + ValidationUtils.assertValid(validator, definition); definition.setInteractionType(InteractionType.OTHER); - var violations = validator.validate(definition); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, definition); } } diff --git a/src/test/java/com/yetanalytics/model/ActivityTest.java b/src/test/java/com/yetanalytics/model/ActivityTest.java index dcf96a3..32c8082 100644 --- a/src/test/java/com/yetanalytics/model/ActivityTest.java +++ b/src/test/java/com/yetanalytics/model/ActivityTest.java @@ -1,14 +1,12 @@ package com.yetanalytics.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Activity; import com.yetanalytics.xapi.model.ActivityDefinition; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class ActivityTest { @@ -17,8 +15,8 @@ public class ActivityTest { private Activity activity; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); definition = new ActivityDefinition(); activity = new Activity(); } @@ -26,17 +24,16 @@ public void initValidator() { @Test public void testActivity() { activity.setId("http://example.org/activity"); - assertTrue(validator.validate(activity).isEmpty()); + ValidationUtils.assertValid(validator, activity); // TODO: Enforce that definitions, as JSON objects, can't be empty // For now we allow them though activity.setDefinition(definition); - assertTrue(validator.validate(activity).isEmpty()); + ValidationUtils.assertValid(validator, activity); } @Test public void testEmptyActivity() { - var violations = validator.validate(activity); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, activity); } } diff --git a/src/test/java/com/yetanalytics/model/AgentTest.java b/src/test/java/com/yetanalytics/model/AgentTest.java index eecf35a..17bfd38 100644 --- a/src/test/java/com/yetanalytics/model/AgentTest.java +++ b/src/test/java/com/yetanalytics/model/AgentTest.java @@ -1,14 +1,12 @@ package com.yetanalytics.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Account; import com.yetanalytics.xapi.model.Agent; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class AgentTest { @@ -16,27 +14,27 @@ public class AgentTest { private Agent agent; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); agent = new Agent(); } @Test public void testMbox() { agent.setMbox("mailto:foo@example.com"); - assertTrue(validator.validate(agent).isEmpty()); + ValidationUtils.assertValid(validator, agent); } @Test public void testMboxSha1Sum() { agent.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); - assertTrue(validator.validate(agent).isEmpty()); + ValidationUtils.assertValid(validator, agent); } @Test public void testOpenid() { agent.setOpenid("http://openid.example.com"); - assertTrue(validator.validate(agent).isEmpty()); + ValidationUtils.assertValid(validator, agent); } @Test @@ -46,28 +44,25 @@ public void testAccount() { account.setName("My Account"); agent.setAccount(account); - assertTrue(validator.validate(agent).isEmpty()); + ValidationUtils.assertValid(validator, agent); } @Test public void testInvalidAccount() { Account account = new Account(); agent.setAccount(account); - var violations = validator.validate(agent); - assertEquals(2, violations.size()); + ValidationUtils.assertInvalid(validator, agent, 2); } @Test public void testNoIFI() { - var violations = validator.validate(agent); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, agent); } @Test public void testMultiIFI() { agent.setMbox("mailto:foo@example.com"); agent.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); - var violations = validator.validate(agent); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, agent); } } diff --git a/src/test/java/com/yetanalytics/model/AttachmentTest.java b/src/test/java/com/yetanalytics/model/AttachmentTest.java index c82f40b..fe71f99 100644 --- a/src/test/java/com/yetanalytics/model/AttachmentTest.java +++ b/src/test/java/com/yetanalytics/model/AttachmentTest.java @@ -2,15 +2,13 @@ import java.util.HashMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Attachment; import com.yetanalytics.xapi.model.LangMap; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class AttachmentTest { @@ -18,8 +16,8 @@ public class AttachmentTest { private Attachment attachment; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); attachment = new Attachment(); } @@ -43,11 +41,12 @@ public void testAttachment() { attachment.setLength(length); attachment.setSha2(sha2); attachment.setFileUrl(fileUrl); - assertTrue(validator.validate(attachment).isEmpty()); + + ValidationUtils.assertValid(validator, attachment); } @Test public void testEmptyAttachment() { - assertEquals(5, validator.validate(attachment).size()); + ValidationUtils.assertInvalid(validator, attachment, 5); } } diff --git a/src/test/java/com/yetanalytics/model/GroupTest.java b/src/test/java/com/yetanalytics/model/GroupTest.java index 8ebbce8..691daf4 100644 --- a/src/test/java/com/yetanalytics/model/GroupTest.java +++ b/src/test/java/com/yetanalytics/model/GroupTest.java @@ -3,16 +3,14 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Account; import com.yetanalytics.xapi.model.Agent; import com.yetanalytics.xapi.model.Group; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class GroupTest { @@ -20,8 +18,8 @@ public class GroupTest { private Group group; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); group = new Group(); } @@ -32,25 +30,25 @@ public void testAnomyousGroup() { memberAgent.setMbox("mailto:mem@example.com"); member.add(memberAgent); group.setMember(member); - assertTrue(validator.validate(group).isEmpty()); + ValidationUtils.assertValid(validator, group); } @Test public void testMbox() { group.setMbox("mailto:foo@example.com"); - assertTrue(validator.validate(group).isEmpty()); + ValidationUtils.assertValid(validator, group); } @Test public void testMboxSha1Sum() { group.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); - assertTrue(validator.validate(group).isEmpty()); + ValidationUtils.assertValid(validator, group); } @Test public void testOpenid() { group.setOpenid("http://openid.example.com"); - assertTrue(validator.validate(group).isEmpty()); + ValidationUtils.assertValid(validator, group); } @Test @@ -60,29 +58,25 @@ public void testAccount() { account.setName("My Account"); group.setAccount(account); - assertTrue(validator.validate(group).isEmpty()); + ValidationUtils.assertValid(validator, group); } @Test public void testInvalidAccount() { Account account = new Account(); group.setAccount(account); - var violations = validator.validate(group); - assertEquals(2, violations.size()); + ValidationUtils.assertInvalid(validator, group, 2); } @Test public void testNoIFI() { // No member array => identified group - var violations = validator.validate(group); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, group); } @Test public void testMultiIFI() { group.setMbox("mailto:foo@example.com"); group.setMbox_sha1sum("767e74eab7081c41e0b83630511139d130249666"); - var violations = validator.validate(group); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, group); } - } diff --git a/src/test/java/com/yetanalytics/model/InteractionComponentTest.java b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java index 8149fed..4183b5b 100644 --- a/src/test/java/com/yetanalytics/model/InteractionComponentTest.java +++ b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java @@ -2,15 +2,13 @@ import java.util.HashMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.InteractionComponent; import com.yetanalytics.xapi.model.LangMap; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class InteractionComponentTest { @@ -18,8 +16,8 @@ public class InteractionComponentTest { private InteractionComponent interactionComponent; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); interactionComponent = new InteractionComponent(); } @@ -29,11 +27,11 @@ public void testInteractionComponent() { desc.put("en-US", "Foo"); interactionComponent.setId("foo"); interactionComponent.setDescription(desc); - assertTrue(validator.validate(interactionComponent).isEmpty()); + ValidationUtils.assertValid(validator, interactionComponent); } @Test public void testEmpytInteractionComponent() { - assertEquals(1, validator.validate(interactionComponent).size()); + ValidationUtils.assertInvalid(validator, interactionComponent); } } diff --git a/src/test/java/com/yetanalytics/model/ResultTest.java b/src/test/java/com/yetanalytics/model/ResultTest.java index c5f0c94..ea2dbd8 100644 --- a/src/test/java/com/yetanalytics/model/ResultTest.java +++ b/src/test/java/com/yetanalytics/model/ResultTest.java @@ -2,15 +2,13 @@ import java.math.BigDecimal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Result; import com.yetanalytics.xapi.model.Score; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class ResultTest { @@ -19,8 +17,8 @@ public class ResultTest { private Score score; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); score = new Score(); result = new Result(); } @@ -35,14 +33,13 @@ public void testResult() { // TODO: setExtensions // TODO: setDuration - assertTrue(validator.validate(result).isEmpty()); + ValidationUtils.assertValid(validator, result); } @Test public void testInvalidScore() { score.setScaled(new BigDecimal(3.0)); result.setScore(score); - assertEquals(1, validator.validate(result).size()); + ValidationUtils.assertInvalid(validator, result); } - } diff --git a/src/test/java/com/yetanalytics/model/ScoreTest.java b/src/test/java/com/yetanalytics/model/ScoreTest.java index 66c85f1..a6e856f 100644 --- a/src/test/java/com/yetanalytics/model/ScoreTest.java +++ b/src/test/java/com/yetanalytics/model/ScoreTest.java @@ -2,14 +2,12 @@ import java.math.BigDecimal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Score; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class ScoreTest { @@ -17,57 +15,52 @@ public class ScoreTest { private Score score; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); score = new Score(); } @Test public void testScore() { - assertTrue(validator.validate(score).isEmpty()); + ValidationUtils.assertValid(validator, score); // TODO: Make invalid score.setMin(new BigDecimal(0)); score.setMax(new BigDecimal(100)); score.setRaw(new BigDecimal(50)); score.setScaled(new BigDecimal(0)); - assertTrue(validator.validate(score).isEmpty()); + ValidationUtils.assertValid(validator, score); } @Test public void testScaledTooSmall() { score.setScaled(new BigDecimal(-2.0)); - var violations = validator.validate(score); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, score); } @Test public void testScaledTooBig() { score.setScaled(new BigDecimal(2.0)); - var violations = validator.validate(score); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, score); } @Test public void testMinBiggerThanMax() { score.setMax(new BigDecimal(0.4)); score.setMin(new BigDecimal(0.6)); - var violations = validator.validate(score); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, score); } @Test public void testRawBiggerThanMax() { score.setMax(new BigDecimal(0.4)); score.setRaw(new BigDecimal(0.6)); - var violations = validator.validate(score); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, score); } @Test public void testMinBiggerThanRaw() { score.setRaw(new BigDecimal(0.4)); score.setMin(new BigDecimal(0.6)); - var violations = validator.validate(score); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, score); } } diff --git a/src/test/java/com/yetanalytics/model/StatementRefTest.java b/src/test/java/com/yetanalytics/model/StatementRefTest.java index 4584ae7..c20fd05 100644 --- a/src/test/java/com/yetanalytics/model/StatementRefTest.java +++ b/src/test/java/com/yetanalytics/model/StatementRefTest.java @@ -1,16 +1,13 @@ package com.yetanalytics.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.util.UUID; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.StatementRef; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class StatementRefTest { @@ -18,8 +15,8 @@ public class StatementRefTest { private StatementRef statementRef; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); statementRef = new StatementRef(); } @@ -27,11 +24,11 @@ public void initValidator() { public void testStatementRef() { String id = "00000000-4000-8000-0000-000000000000"; statementRef.setId(UUID.fromString(id)); - assertTrue(validator.validate(statementRef).isEmpty()); + ValidationUtils.assertValid(validator, statementRef); } @Test public void testEmptyStatementRef() { - assertEquals(1, validator.validate(statementRef).size()); + ValidationUtils.assertInvalid(validator, statementRef); } } diff --git a/src/test/java/com/yetanalytics/model/StatementResultTest.java b/src/test/java/com/yetanalytics/model/StatementResultTest.java index b9a9d0f..f39a3d6 100644 --- a/src/test/java/com/yetanalytics/model/StatementResultTest.java +++ b/src/test/java/com/yetanalytics/model/StatementResultTest.java @@ -3,18 +3,16 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Activity; import com.yetanalytics.xapi.model.Agent; import com.yetanalytics.xapi.model.Statement; import com.yetanalytics.xapi.model.StatementResult; import com.yetanalytics.xapi.model.Verb; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class StatementResultTest { @@ -22,8 +20,8 @@ public class StatementResultTest { private StatementResult statementResult; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); statementResult = new StatementResult(); } @@ -47,11 +45,11 @@ public void testStatementResult() { statements.add(statement); statementResult.setStatements(statements); - assertTrue(validator.validate(statements).isEmpty()); + ValidationUtils.assertValid(validator, statementResult); } @Test public void testEmptyStatementResult() { - assertEquals(1, validator.validate(statementResult).size()); + ValidationUtils.assertInvalid(validator, statementResult); } } diff --git a/src/test/java/com/yetanalytics/model/StatementTest.java b/src/test/java/com/yetanalytics/model/StatementTest.java index 780d101..33445e2 100644 --- a/src/test/java/com/yetanalytics/model/StatementTest.java +++ b/src/test/java/com/yetanalytics/model/StatementTest.java @@ -4,11 +4,11 @@ import java.util.List; import java.util.UUID; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.Account; import com.yetanalytics.xapi.model.Activity; import com.yetanalytics.xapi.model.Agent; @@ -18,7 +18,6 @@ import com.yetanalytics.xapi.model.StatementRef; import com.yetanalytics.xapi.model.Verb; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class StatementTest { @@ -33,8 +32,8 @@ private StatementRef genericStatementRef() { } @Before - public void initStatement() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); statement = new Statement(); // Valid statement by default @@ -54,7 +53,7 @@ public void initStatement() { @Test public void testStatement() { - assertTrue(validator.validate(statement).isEmpty()); + ValidationUtils.assertValid(validator, statement); } @Test @@ -62,7 +61,7 @@ public void testEmptyStatement() { statement.setActor(null); statement.setVerb(null); statement.setObject(null); - assertEquals(3, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement, 3); } @Test @@ -71,12 +70,12 @@ public void testVoidingStatement() { voidingVerb.setId(Verb.VOIDING_VERB_IRI); statement.setVerb(voidingVerb); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); StatementRef statementRef = genericStatementRef(); statement.setObject(statementRef); - assertTrue(validator.validate(statement).isEmpty()); + ValidationUtils.assertValid(validator, statement); } @Test @@ -84,12 +83,13 @@ public void testValidContextRevision() { Context context = new Context(); context.setRevision("myRevision"); statement.setContext(context); + ValidationUtils.assertValid(validator, statement); assertTrue(validator.validate(statement).isEmpty()); StatementRef statementRef = genericStatementRef(); statement.setObject(statementRef); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); } @Test @@ -102,7 +102,7 @@ public void testValidContextPlatform() { StatementRef statementRef = genericStatementRef(); statement.setObject(statementRef); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); } @Test @@ -123,7 +123,7 @@ public void testValidAuthority() { groupAuthMember.add(agentAuthority); groupAuthority.setMember(groupAuthMember); statement.setAuthority(groupAuthority); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); // Need to add second member Agent nonConsumer = new Agent(); @@ -133,12 +133,12 @@ public void testValidAuthority() { // At least one member needs to have an Account groupAuthMember.set(0, nonConsumer); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); // Cannot have three (or more) members groupAuthMember.set(0, agentAuthority); groupAuthMember.add(nonConsumer); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); } @Test @@ -159,20 +159,20 @@ public void testValidSubStatement() { UUID id = UUID.fromString("00000000-4000-8000-0000-000000000000"); subStatement.setId(id); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); // TODO: test Stored presence String version = "1.0.3"; subStatement.setId(null); subStatement.setVersion(version); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); Agent authority = new Agent(); authority.setMbox("mailto:myauthority@example.com"); subStatement.setVersion(null); subStatement.setAuthority(authority); - assertEquals(1, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement); Statement subSubStatement = new Statement(); Agent actor2 = new Agent(); @@ -187,6 +187,6 @@ public void testValidSubStatement() { subStatement.setAuthority(null); subStatement.setObject(subStatement); // TODO: Dig deeper why this is 2 errors and not 1 - assertEquals(2, validator.validate(statement).size()); + ValidationUtils.assertInvalid(validator, statement, 2); } } diff --git a/src/test/java/com/yetanalytics/model/VerbTest.java b/src/test/java/com/yetanalytics/model/VerbTest.java index 7bac522..d8920ca 100644 --- a/src/test/java/com/yetanalytics/model/VerbTest.java +++ b/src/test/java/com/yetanalytics/model/VerbTest.java @@ -2,15 +2,13 @@ import java.util.HashMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.yetanalytics.util.ValidationUtils; import com.yetanalytics.xapi.model.LangMap; import com.yetanalytics.xapi.model.Verb; -import jakarta.validation.Validation; import jakarta.validation.Validator; public class VerbTest { @@ -18,8 +16,8 @@ public class VerbTest { private Verb verb; @Before - public void initValidator() { - validator = Validation.buildDefaultValidatorFactory().getValidator(); + public void init() { + validator = ValidationUtils.getValidator(); verb = new Verb(); } @@ -30,12 +28,11 @@ public void testVerb() { verb.setId("http://example.com/verb"); verb.setDisplay(display); - assertTrue(validator.validate(verb).isEmpty()); + ValidationUtils.assertValid(validator, verb); } @Test public void testEmptyVerb() { - var violations = validator.validate(verb); - assertEquals(1, violations.size()); + ValidationUtils.assertInvalid(validator, verb); } } diff --git a/src/test/java/com/yetanalytics/util/ValidationUtils.java b/src/test/java/com/yetanalytics/util/ValidationUtils.java new file mode 100644 index 0000000..e3f7b5f --- /dev/null +++ b/src/test/java/com/yetanalytics/util/ValidationUtils.java @@ -0,0 +1,26 @@ +package com.yetanalytics.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; + +public class ValidationUtils { + + public static Validator getValidator() { + return Validation.buildDefaultValidatorFactory().getValidator(); + } + + public static void assertValid(Validator validator, Object object) { + assertTrue(validator.validate(object).isEmpty()); + } + + public static void assertInvalid(Validator validator, Object object) { + assertInvalid(validator, object, 1); + } + + public static void assertInvalid(Validator validator, Object object, int numErrors) { + assertEquals(numErrors, validator.validate(object).size()); + } +} From 131c3804b2986107767f51bf003b75de5c976e79 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Mon, 9 Dec 2024 17:18:21 -0500 Subject: [PATCH 20/22] Add isEmpty function to validate that JSON objects are not empty --- .../xapi/model/AbstractActor.java | 8 ++++++++ .../xapi/model/AbstractObject.java | 4 +++- .../com/yetanalytics/xapi/model/Account.java | 9 ++++++++- .../com/yetanalytics/xapi/model/Activity.java | 7 +++++++ .../xapi/model/ActivityDefinition.java | 13 +++++++++++- .../com/yetanalytics/xapi/model/Agent.java | 7 +++++++ .../yetanalytics/xapi/model/Attachment.java | 17 ++++++++++++++-- .../com/yetanalytics/xapi/model/Context.java | 20 ++++++++++++++++++- .../xapi/model/ContextActivities.java | 13 +++++++++++- .../yetanalytics/xapi/model/Extensions.java | 10 +++++++++- .../com/yetanalytics/xapi/model/Group.java | 8 ++++++++ .../xapi/model/InteractionComponent.java | 9 +++++++-- .../yetanalytics/xapi/model/JSONObject.java | 5 +++++ .../com/yetanalytics/xapi/model/LangMap.java | 10 +++++++++- .../com/yetanalytics/xapi/model/Result.java | 16 ++++++++++++++- .../com/yetanalytics/xapi/model/Score.java | 9 ++++++++- .../yetanalytics/xapi/model/Statement.java | 19 ++++++++++++++++++ .../yetanalytics/xapi/model/StatementRef.java | 7 +++++++ .../xapi/model/StatementResult.java | 9 ++++++++- .../com/yetanalytics/xapi/model/Verb.java | 10 ++++++++-- .../yetanalytics/XapiSerializationTest.java | 5 +++-- .../com/yetanalytics/model/AccountTest.java | 2 +- .../model/ActivityDefinitionTest.java | 2 +- .../com/yetanalytics/model/ActivityTest.java | 6 +++--- .../com/yetanalytics/model/AgentTest.java | 6 ++++-- .../yetanalytics/model/AttachmentTest.java | 3 ++- .../com/yetanalytics/model/GroupTest.java | 6 ++++-- .../model/InteractionComponentTest.java | 3 ++- .../com/yetanalytics/model/ScoreTest.java | 7 +++++-- .../yetanalytics/model/StatementRefTest.java | 3 ++- .../model/StatementResultTest.java | 3 ++- .../com/yetanalytics/model/StatementTest.java | 3 ++- .../java/com/yetanalytics/model/VerbTest.java | 3 ++- 33 files changed, 227 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/yetanalytics/xapi/model/JSONObject.java diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java index 7e96a6b..0f18e1d 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java @@ -79,4 +79,12 @@ protected int countIFIs() { } public abstract boolean isValidAuthority(); + + @Override + public boolean isEmpty() { + return ( + mbox == null && mbox_sha1sum == null && + openid == null && account == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java b/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java index 068a861..69ebebb 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java @@ -7,7 +7,7 @@ * Abstract Class for serialization and deserialization of xAPI Objects */ @JsonDeserialize(using = AbstractObjectDeserializer.class) -public class AbstractObject { +public abstract class AbstractObject implements JSONObject { private ObjectType objectType; @@ -18,4 +18,6 @@ public void setObjectType(ObjectType objectType) { this.objectType = objectType; } + @Override + public abstract boolean isEmpty(); } diff --git a/src/main/java/com/yetanalytics/xapi/model/Account.java b/src/main/java/com/yetanalytics/xapi/model/Account.java index 5470ad3..eff18d8 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Account.java +++ b/src/main/java/com/yetanalytics/xapi/model/Account.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -10,7 +11,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Account { +public class Account implements JSONObject { @NotNull private String homePage; @@ -30,4 +31,10 @@ public String getName() { public void setName(String name) { this.name = name; } + + @Override + @AssertFalse + public boolean isEmpty() { + return homePage == null && name == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Activity.java b/src/main/java/com/yetanalytics/xapi/model/Activity.java index b730b25..4385d96 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Activity.java +++ b/src/main/java/com/yetanalytics/xapi/model/Activity.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -33,4 +34,10 @@ public ActivityDefinition getDefinition() { public void setDefinition(ActivityDefinition definition) { this.definition = definition; } + + @Override + @AssertFalse + public boolean isEmpty() { + return id == null && definition == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java index b83e473..5439f8d 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java +++ b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.AssertTrue; /** @@ -12,7 +13,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class ActivityDefinition { +public class ActivityDefinition implements JSONObject { private LangMap name; private LangMap description; @@ -162,6 +163,16 @@ private boolean isNoInteraction() { ); } + @Override + @AssertFalse + public boolean isEmpty() { + return ( + name == null && description == null && + type == null && moreInfo == null && extensions == null && + interactionType == null && isNoInteraction() + ); + } + @AssertTrue public boolean isValidInteractionActivity() { if (interactionType == null) { diff --git a/src/main/java/com/yetanalytics/xapi/model/Agent.java b/src/main/java/com/yetanalytics/xapi/model/Agent.java index a234efb..a7ae389 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Agent.java +++ b/src/main/java/com/yetanalytics/xapi/model/Agent.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.AssertTrue; /** @@ -17,6 +18,12 @@ public class Agent extends AbstractActor { // Validation + @Override + @AssertFalse + public boolean isEmpty() { + return super.isEmpty(); + } + /** * Assertion that the Agent has only 1 Inverse Functional Identifier (IFI). * @return true if the Agent has exactly 1 IFI, false otherwise diff --git a/src/main/java/com/yetanalytics/xapi/model/Attachment.java b/src/main/java/com/yetanalytics/xapi/model/Attachment.java index 149f05a..d42c66a 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Attachment.java +++ b/src/main/java/com/yetanalytics/xapi/model/Attachment.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -10,7 +11,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Attachment { +public class Attachment implements JSONObject { @NotNull private String usageType; @@ -68,5 +69,17 @@ public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; } - + @Override + @AssertFalse + public boolean isEmpty() { + return ( + usageType == null && + display == null && + description == null && + contentType == null && + length == null && + sha2 == null && + fileUrl == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Context.java b/src/main/java/com/yetanalytics/xapi/model/Context.java index da73c63..0aaee79 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Context.java +++ b/src/main/java/com/yetanalytics/xapi/model/Context.java @@ -1,15 +1,18 @@ package com.yetanalytics.xapi.model; import java.util.UUID; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; + /** * Class representation of the Context Component of the * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Context { +public class Context implements JSONObject { private UUID registration; private AbstractActor instructor; @@ -76,4 +79,19 @@ public void setExtensions(Extensions extensions) { this.extensions = extensions; } + @Override + @AssertFalse + public boolean isEmpty() { + return ( + registration == null && + instructor == null && + team == null && + contextActivities == null && + revision == null && + platform == null && + language == null && + statement == null && + extensions == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java b/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java index eb65d31..47f6104 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java +++ b/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java @@ -4,6 +4,9 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.ContextActivityListDeserializer; + +import jakarta.validation.constraints.AssertFalse; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -12,7 +15,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class ContextActivities { +public class ContextActivities implements JSONObject { @JsonDeserialize(using = ContextActivityListDeserializer.class) private List parent; @@ -48,4 +51,12 @@ public void setOther(List other) { this.other = other; } + @Override + @AssertFalse + public boolean isEmpty() { + return ( + parent == null && grouping == null && + category == null && other == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Extensions.java b/src/main/java/com/yetanalytics/xapi/model/Extensions.java index 09ee477..0156355 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Extensions.java +++ b/src/main/java/com/yetanalytics/xapi/model/Extensions.java @@ -13,6 +13,8 @@ import com.yetanalytics.xapi.model.serializers.ExtensionSerializer; import com.yetanalytics.xapi.util.Mapper; +import jakarta.validation.constraints.AssertFalse; + /** * A wrapper object for using xAPI Extensions. * @@ -22,7 +24,7 @@ */ @JsonDeserialize(using = ExtensionDeserializer.class) @JsonSerialize(using = ExtensionSerializer.class) -public class Extensions { +public class Extensions implements JSONObject { private Map extMap = new HashMap<>(); @@ -96,4 +98,10 @@ public Set getKeys() { public Map getMap() { return extMap; } + + @Override + @AssertFalse + public boolean isEmpty() { + return extMap.isEmpty(); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Group.java b/src/main/java/com/yetanalytics/xapi/model/Group.java index 333476e..7baae6e 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Group.java +++ b/src/main/java/com/yetanalytics/xapi/model/Group.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.AssertTrue; /** @@ -48,4 +49,11 @@ public boolean isValidAuthority() { ) ); } + + @Override + @AssertFalse + public boolean isEmpty() { + // zero-length member arrays still count as non-empty + return super.isEmpty() && member == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java index 0966dc4..6dd3cfd 100644 --- a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java +++ b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -9,7 +10,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class InteractionComponent { +public class InteractionComponent implements JSONObject { @NotNull private String id; @@ -32,5 +33,9 @@ public void setDescription(LangMap description) { this.description = description; } - + @Override + @AssertFalse + public boolean isEmpty() { + return id == null && description == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/JSONObject.java b/src/main/java/com/yetanalytics/xapi/model/JSONObject.java new file mode 100644 index 0000000..157f6db --- /dev/null +++ b/src/main/java/com/yetanalytics/xapi/model/JSONObject.java @@ -0,0 +1,5 @@ +package com.yetanalytics.xapi.model; + +public interface JSONObject { + public boolean isEmpty(); +} diff --git a/src/main/java/com/yetanalytics/xapi/model/LangMap.java b/src/main/java/com/yetanalytics/xapi/model/LangMap.java index cb451a4..6c964f5 100644 --- a/src/main/java/com/yetanalytics/xapi/model/LangMap.java +++ b/src/main/java/com/yetanalytics/xapi/model/LangMap.java @@ -9,6 +9,8 @@ import com.yetanalytics.xapi.model.deserializers.LangMapDeserializer; import com.yetanalytics.xapi.model.serializers.LangMapSerializer; +import jakarta.validation.constraints.AssertFalse; + /** * Java wrapper object for the * xAPI Language Map object. @@ -18,7 +20,7 @@ */ @JsonDeserialize(using = LangMapDeserializer.class) @JsonSerialize(using = LangMapSerializer.class) -public class LangMap { +public class LangMap implements JSONObject { private HashMap languageHashMap = new HashMap<>(); @@ -71,4 +73,10 @@ public Set getLanguageCodes() { public Map getMap() { return languageHashMap; } + + @Override + @AssertFalse + public boolean isEmpty() { + return languageHashMap.isEmpty(); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Result.java b/src/main/java/com/yetanalytics/xapi/model/Result.java index b4e47db..8df9f04 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Result.java +++ b/src/main/java/com/yetanalytics/xapi/model/Result.java @@ -4,13 +4,14 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertFalse; /** * Class representation of the Result component of the * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Result { +public class Result implements JSONObject { @Valid private Score score; @@ -56,4 +57,17 @@ public Extensions getExtensions() { public void setExtensions(Extensions extensions) { this.extensions = extensions; } + + @Override + @AssertFalse + public boolean isEmpty() { + return ( + score == null && + success == null && + completion == null && + response == null && + duration == null && + extensions == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Score.java b/src/main/java/com/yetanalytics/xapi/model/Score.java index 1388a56..043af7d 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Score.java +++ b/src/main/java/com/yetanalytics/xapi/model/Score.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMin; @@ -14,7 +15,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Score { +public class Score implements JSONObject { private BigDecimal raw; private BigDecimal min; @@ -77,4 +78,10 @@ public boolean isMinLessThanMax() { return true; } } + + @Override + @AssertFalse + public boolean isEmpty() { + return raw == null && min == null && max == null && scaled == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Statement.java b/src/main/java/com/yetanalytics/xapi/model/Statement.java index 7031777..2465dc4 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Statement.java +++ b/src/main/java/com/yetanalytics/xapi/model/Statement.java @@ -11,6 +11,7 @@ import com.yetanalytics.xapi.model.serializers.DateTimeSerializer; import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; @@ -204,4 +205,22 @@ public boolean isValidSubStatement() { return true; } } + + @Override + @AssertFalse + public boolean isEmpty() { + return ( + id == null && + actor == null && + verb == null && + object == null && + context == null && + result == null && + authority == null && + timestamp == null && + stored == null && + version == null && + attachments == null + ); + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java index 477a7f5..2044fdd 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -25,4 +26,10 @@ public UUID getId() { public void setId(UUID id) { this.id = id; } + + @Override + @AssertFalse + public boolean isEmpty() { + return id == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java index 6272807..e29efb5 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java @@ -5,13 +5,14 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** * Class representation of a StatementResult from the 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class StatementResult { +public class StatementResult implements JSONObject { @NotNull private List statements; @@ -33,4 +34,10 @@ public String getMore() { public void setMore(String more) { this.more = more; } + + @Override + @AssertFalse + public boolean isEmpty() { + return statements == null && more == null; + } } diff --git a/src/main/java/com/yetanalytics/xapi/model/Verb.java b/src/main/java/com/yetanalytics/xapi/model/Verb.java index e6d1178..cd8c0ab 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Verb.java +++ b/src/main/java/com/yetanalytics/xapi/model/Verb.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.LangMapDeserializer; +import jakarta.validation.constraints.AssertFalse; import jakarta.validation.constraints.NotNull; /** @@ -12,7 +13,7 @@ * 9274.1.1 xAPI Specification. */ @JsonInclude(Include.NON_NULL) -public class Verb { +public class Verb implements JSONObject { public static final String VOIDING_VERB_IRI = "http://adlnet.gov/expapi/verbs/voided"; @@ -41,5 +42,10 @@ public void setDisplay(LangMap display) { public boolean isVoiding() { return id == VOIDING_VERB_IRI; } - + + @Override + @AssertFalse + public boolean isEmpty() { + return id == null && display == null; + } } diff --git a/src/test/java/com/yetanalytics/XapiSerializationTest.java b/src/test/java/com/yetanalytics/XapiSerializationTest.java index cedc222..30dc13f 100644 --- a/src/test/java/com/yetanalytics/XapiSerializationTest.java +++ b/src/test/java/com/yetanalytics/XapiSerializationTest.java @@ -1,7 +1,7 @@ package com.yetanalytics; -import java.io.IOException; import java.io.File; +import java.io.IOException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -9,7 +9,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.flipkart.zjsonpatch.JsonDiff; import com.yetanalytics.util.TestFileUtils; -import com.yetanalytics.xapi.model.*; +import com.yetanalytics.xapi.model.Statement; +import com.yetanalytics.xapi.model.StatementResult; import com.yetanalytics.xapi.util.Mapper; import junit.framework.Test; diff --git a/src/test/java/com/yetanalytics/model/AccountTest.java b/src/test/java/com/yetanalytics/model/AccountTest.java index fa54cb3..bab6f03 100644 --- a/src/test/java/com/yetanalytics/model/AccountTest.java +++ b/src/test/java/com/yetanalytics/model/AccountTest.java @@ -27,6 +27,6 @@ public void testValidAccount() { @Test public void testEmptyAccount() { - ValidationUtils.assertInvalid(validator, account, 2); + ValidationUtils.assertInvalid(validator, account, 3); } } diff --git a/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java index 19ab497..2baeb90 100644 --- a/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java +++ b/src/test/java/com/yetanalytics/model/ActivityDefinitionTest.java @@ -43,7 +43,7 @@ public void init() { @Test public void testEmptyDefinition() { - ValidationUtils.assertValid(validator, definition); + ValidationUtils.assertInvalid(validator, definition); } @Test diff --git a/src/test/java/com/yetanalytics/model/ActivityTest.java b/src/test/java/com/yetanalytics/model/ActivityTest.java index 32c8082..e7a226c 100644 --- a/src/test/java/com/yetanalytics/model/ActivityTest.java +++ b/src/test/java/com/yetanalytics/model/ActivityTest.java @@ -26,14 +26,14 @@ public void testActivity() { activity.setId("http://example.org/activity"); ValidationUtils.assertValid(validator, activity); - // TODO: Enforce that definitions, as JSON objects, can't be empty - // For now we allow them though activity.setDefinition(definition); + definition.setMoreInfo("https://yetanalytics.com"); ValidationUtils.assertValid(validator, activity); } @Test public void testEmptyActivity() { - ValidationUtils.assertInvalid(validator, activity); + // One error for empty object, one error for missing ID + ValidationUtils.assertInvalid(validator, activity, 2); } } diff --git a/src/test/java/com/yetanalytics/model/AgentTest.java b/src/test/java/com/yetanalytics/model/AgentTest.java index 17bfd38..9a93650 100644 --- a/src/test/java/com/yetanalytics/model/AgentTest.java +++ b/src/test/java/com/yetanalytics/model/AgentTest.java @@ -51,12 +51,14 @@ public void testAccount() { public void testInvalidAccount() { Account account = new Account(); agent.setAccount(account); - ValidationUtils.assertInvalid(validator, agent, 2); + // One error for empty account, one error each for missing properties + ValidationUtils.assertInvalid(validator, agent, 3); } @Test public void testNoIFI() { - ValidationUtils.assertInvalid(validator, agent); + // One error for empty agent, one error for missing IFI + ValidationUtils.assertInvalid(validator, agent, 2); } @Test diff --git a/src/test/java/com/yetanalytics/model/AttachmentTest.java b/src/test/java/com/yetanalytics/model/AttachmentTest.java index fe71f99..e03e389 100644 --- a/src/test/java/com/yetanalytics/model/AttachmentTest.java +++ b/src/test/java/com/yetanalytics/model/AttachmentTest.java @@ -47,6 +47,7 @@ public void testAttachment() { @Test public void testEmptyAttachment() { - ValidationUtils.assertInvalid(validator, attachment, 5); + // One error for empty attachment, one error each for null properties + ValidationUtils.assertInvalid(validator, attachment, 6); } } diff --git a/src/test/java/com/yetanalytics/model/GroupTest.java b/src/test/java/com/yetanalytics/model/GroupTest.java index 691daf4..a2c11da 100644 --- a/src/test/java/com/yetanalytics/model/GroupTest.java +++ b/src/test/java/com/yetanalytics/model/GroupTest.java @@ -65,12 +65,14 @@ public void testAccount() { public void testInvalidAccount() { Account account = new Account(); group.setAccount(account); - ValidationUtils.assertInvalid(validator, group, 2); + // One error for empty account, one error each for missing properties + ValidationUtils.assertInvalid(validator, group, 3); } @Test public void testNoIFI() { // No member array => identified group - ValidationUtils.assertInvalid(validator, group); + // One error for empty group object, one error for no IFI + ValidationUtils.assertInvalid(validator, group, 2); } @Test diff --git a/src/test/java/com/yetanalytics/model/InteractionComponentTest.java b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java index 4183b5b..e74a1ad 100644 --- a/src/test/java/com/yetanalytics/model/InteractionComponentTest.java +++ b/src/test/java/com/yetanalytics/model/InteractionComponentTest.java @@ -32,6 +32,7 @@ public void testInteractionComponent() { @Test public void testEmpytInteractionComponent() { - ValidationUtils.assertInvalid(validator, interactionComponent); + // One error for empty component, one error for missing ID + ValidationUtils.assertInvalid(validator, interactionComponent, 2); } } diff --git a/src/test/java/com/yetanalytics/model/ScoreTest.java b/src/test/java/com/yetanalytics/model/ScoreTest.java index a6e856f..0cb4f9b 100644 --- a/src/test/java/com/yetanalytics/model/ScoreTest.java +++ b/src/test/java/com/yetanalytics/model/ScoreTest.java @@ -22,8 +22,6 @@ public void init() { @Test public void testScore() { - ValidationUtils.assertValid(validator, score); // TODO: Make invalid - score.setMin(new BigDecimal(0)); score.setMax(new BigDecimal(100)); score.setRaw(new BigDecimal(50)); @@ -31,6 +29,11 @@ public void testScore() { ValidationUtils.assertValid(validator, score); } + @Test + public void testEmptyScore() { + ValidationUtils.assertInvalid(validator, score); + } + @Test public void testScaledTooSmall() { score.setScaled(new BigDecimal(-2.0)); diff --git a/src/test/java/com/yetanalytics/model/StatementRefTest.java b/src/test/java/com/yetanalytics/model/StatementRefTest.java index c20fd05..bca7432 100644 --- a/src/test/java/com/yetanalytics/model/StatementRefTest.java +++ b/src/test/java/com/yetanalytics/model/StatementRefTest.java @@ -29,6 +29,7 @@ public void testStatementRef() { @Test public void testEmptyStatementRef() { - ValidationUtils.assertInvalid(validator, statementRef); + // One error for empty object, one error for missing ID + ValidationUtils.assertInvalid(validator, statementRef, 2); } } diff --git a/src/test/java/com/yetanalytics/model/StatementResultTest.java b/src/test/java/com/yetanalytics/model/StatementResultTest.java index f39a3d6..167f3e9 100644 --- a/src/test/java/com/yetanalytics/model/StatementResultTest.java +++ b/src/test/java/com/yetanalytics/model/StatementResultTest.java @@ -50,6 +50,7 @@ public void testStatementResult() { @Test public void testEmptyStatementResult() { - ValidationUtils.assertInvalid(validator, statementResult); + // One error for empty statement res, one error for missing statement + ValidationUtils.assertInvalid(validator, statementResult, 2); } } diff --git a/src/test/java/com/yetanalytics/model/StatementTest.java b/src/test/java/com/yetanalytics/model/StatementTest.java index 33445e2..7be6481 100644 --- a/src/test/java/com/yetanalytics/model/StatementTest.java +++ b/src/test/java/com/yetanalytics/model/StatementTest.java @@ -61,7 +61,8 @@ public void testEmptyStatement() { statement.setActor(null); statement.setVerb(null); statement.setObject(null); - ValidationUtils.assertInvalid(validator, statement, 3); + // One error for empty statement, one error each for missing property + ValidationUtils.assertInvalid(validator, statement, 4); } @Test diff --git a/src/test/java/com/yetanalytics/model/VerbTest.java b/src/test/java/com/yetanalytics/model/VerbTest.java index d8920ca..88bd0f1 100644 --- a/src/test/java/com/yetanalytics/model/VerbTest.java +++ b/src/test/java/com/yetanalytics/model/VerbTest.java @@ -33,6 +33,7 @@ public void testVerb() { @Test public void testEmptyVerb() { - ValidationUtils.assertInvalid(validator, verb); + // One error for empty verb, one error for missing ID + ValidationUtils.assertInvalid(validator, verb, 2); } } From 90704aa5d9ce8f4e414c05d286cc8a7e3083d2ac Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Tue, 10 Dec 2024 10:06:19 -0500 Subject: [PATCH 21/22] Make statement's own isValidSubStmt method --- .../com/yetanalytics/xapi/model/Statement.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/yetanalytics/xapi/model/Statement.java b/src/main/java/com/yetanalytics/xapi/model/Statement.java index 2465dc4..1150e3d 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Statement.java +++ b/src/main/java/com/yetanalytics/xapi/model/Statement.java @@ -186,6 +186,16 @@ public boolean isValidAuthority() { return authority == null || authority.isValidAuthority(); } + private boolean isValidSubStmt() { + return ( + id == null && + stored == null && + version == null && + authority == null && + !(object instanceof Statement) + ); + } + // TODO: Validate this on the SubStatement itself // (e.g. setting the objectType field) @AssertTrue @@ -194,13 +204,7 @@ public boolean isValidSubStatement() { // TODO: If object is true... if (object instanceof Statement) { Statement subStatement = (Statement) object; - return ( - subStatement.getId() == null && - subStatement.getStored() == null && - subStatement.getVersion() == null && - subStatement.getAuthority() == null && - !(subStatement.getObject() instanceof Statement) - ); + return subStatement.isValidSubStmt(); } else { return true; } From 46b9f84b1f3b1c75ab4e3ee9845dd818f148b0e5 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Tue, 10 Dec 2024 10:24:33 -0500 Subject: [PATCH 22/22] Apply JsonIgnore annotation to prevent Jackson for serializing extra methods --- .../java/com/yetanalytics/xapi/model/AbstractActor.java | 2 ++ .../java/com/yetanalytics/xapi/model/AbstractObject.java | 2 ++ src/main/java/com/yetanalytics/xapi/model/Account.java | 2 ++ src/main/java/com/yetanalytics/xapi/model/Activity.java | 2 ++ .../com/yetanalytics/xapi/model/ActivityDefinition.java | 3 +++ src/main/java/com/yetanalytics/xapi/model/Agent.java | 4 ++++ src/main/java/com/yetanalytics/xapi/model/Attachment.java | 4 ++++ src/main/java/com/yetanalytics/xapi/model/Context.java | 2 ++ .../com/yetanalytics/xapi/model/ContextActivities.java | 7 ++++--- src/main/java/com/yetanalytics/xapi/model/Extensions.java | 2 ++ src/main/java/com/yetanalytics/xapi/model/Group.java | 4 ++++ .../com/yetanalytics/xapi/model/InteractionComponent.java | 4 ++++ src/main/java/com/yetanalytics/xapi/model/LangMap.java | 2 ++ src/main/java/com/yetanalytics/xapi/model/Result.java | 4 ++++ src/main/java/com/yetanalytics/xapi/model/Score.java | 5 +++++ src/main/java/com/yetanalytics/xapi/model/Statement.java | 7 +++++++ .../java/com/yetanalytics/xapi/model/StatementRef.java | 2 ++ .../java/com/yetanalytics/xapi/model/StatementResult.java | 2 ++ src/main/java/com/yetanalytics/xapi/model/Verb.java | 5 +++++ 19 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java index 0f18e1d..c8285c6 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractActor.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.AbstractActorDeserializer; @@ -81,6 +82,7 @@ protected int countIFIs() { public abstract boolean isValidAuthority(); @Override + @JsonIgnore public boolean isEmpty() { return ( mbox == null && mbox_sha1sum == null && diff --git a/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java b/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java index 69ebebb..c96899f 100644 --- a/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java +++ b/src/main/java/com/yetanalytics/xapi/model/AbstractObject.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.AbstractObjectDeserializer; @@ -19,5 +20,6 @@ public void setObjectType(ObjectType objectType) { } @Override + @JsonIgnore public abstract boolean isEmpty(); } diff --git a/src/main/java/com/yetanalytics/xapi/model/Account.java b/src/main/java/com/yetanalytics/xapi/model/Account.java index eff18d8..eaf033a 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Account.java +++ b/src/main/java/com/yetanalytics/xapi/model/Account.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -33,6 +34,7 @@ public void setName(String name) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return homePage == null && name == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/Activity.java b/src/main/java/com/yetanalytics/xapi/model/Activity.java index 4385d96..28aff1c 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Activity.java +++ b/src/main/java/com/yetanalytics/xapi/model/Activity.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -36,6 +37,7 @@ public void setDefinition(ActivityDefinition definition) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return id == null && definition == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java index 5439f8d..de24997 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java +++ b/src/main/java/com/yetanalytics/xapi/model/ActivityDefinition.java @@ -2,6 +2,7 @@ import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -164,6 +165,7 @@ private boolean isNoInteraction() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( @@ -173,6 +175,7 @@ public boolean isEmpty() { ); } + @JsonIgnore @AssertTrue public boolean isValidInteractionActivity() { if (interactionType == null) { diff --git a/src/main/java/com/yetanalytics/xapi/model/Agent.java b/src/main/java/com/yetanalytics/xapi/model/Agent.java index a7ae389..f4c8170 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Agent.java +++ b/src/main/java/com/yetanalytics/xapi/model/Agent.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -19,6 +20,7 @@ public class Agent extends AbstractActor { // Validation @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return super.isEmpty(); @@ -28,12 +30,14 @@ public boolean isEmpty() { * Assertion that the Agent has only 1 Inverse Functional Identifier (IFI). * @return true if the Agent has exactly 1 IFI, false otherwise */ + @JsonIgnore @AssertTrue public boolean isIdentifiedAgent() { return countIFIs() == 1; } @Override + @JsonIgnore public boolean isValidAuthority() { return true; } diff --git a/src/main/java/com/yetanalytics/xapi/model/Attachment.java b/src/main/java/com/yetanalytics/xapi/model/Attachment.java index d42c66a..84fa87c 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Attachment.java +++ b/src/main/java/com/yetanalytics/xapi/model/Attachment.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -69,7 +70,10 @@ public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; } + // Validation + @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( diff --git a/src/main/java/com/yetanalytics/xapi/model/Context.java b/src/main/java/com/yetanalytics/xapi/model/Context.java index 0aaee79..6b1ff41 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Context.java +++ b/src/main/java/com/yetanalytics/xapi/model/Context.java @@ -2,6 +2,7 @@ import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -80,6 +81,7 @@ public void setExtensions(Extensions extensions) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( diff --git a/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java b/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java index 47f6104..6a6cb37 100644 --- a/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java +++ b/src/main/java/com/yetanalytics/xapi/model/ContextActivities.java @@ -2,14 +2,14 @@ import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.yetanalytics.xapi.model.deserializers.ContextActivityListDeserializer; import jakarta.validation.constraints.AssertFalse; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - /** * Class representation of the Context Activities Component of the * 9274.1.1 xAPI Specification. @@ -52,6 +52,7 @@ public void setOther(List other) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( diff --git a/src/main/java/com/yetanalytics/xapi/model/Extensions.java b/src/main/java/com/yetanalytics/xapi/model/Extensions.java index 0156355..72966e7 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Extensions.java +++ b/src/main/java/com/yetanalytics/xapi/model/Extensions.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -100,6 +101,7 @@ public Map getMap() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return extMap.isEmpty(); diff --git a/src/main/java/com/yetanalytics/xapi/model/Group.java b/src/main/java/com/yetanalytics/xapi/model/Group.java index 7baae6e..bb3a8e6 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Group.java +++ b/src/main/java/com/yetanalytics/xapi/model/Group.java @@ -2,6 +2,7 @@ import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -27,6 +28,7 @@ public void setMember(List member) { this.member = member; } + @JsonIgnore @AssertTrue public boolean isAnonymousOrIdentifiedGroup() { return ( @@ -40,6 +42,7 @@ private boolean isValidConsumer(Agent consumer) { } @Override + @JsonIgnore public boolean isValidAuthority() { return ( member.size() == 2 && @@ -51,6 +54,7 @@ public boolean isValidAuthority() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { // zero-length member arrays still count as non-empty diff --git a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java index 6dd3cfd..2bbcbb9 100644 --- a/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java +++ b/src/main/java/com/yetanalytics/xapi/model/InteractionComponent.java @@ -1,4 +1,5 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -33,7 +34,10 @@ public void setDescription(LangMap description) { this.description = description; } + // Validation + @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return id == null && description == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/LangMap.java b/src/main/java/com/yetanalytics/xapi/model/LangMap.java index 6c964f5..2a94575 100644 --- a/src/main/java/com/yetanalytics/xapi/model/LangMap.java +++ b/src/main/java/com/yetanalytics/xapi/model/LangMap.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.yetanalytics.xapi.model.deserializers.LangMapDeserializer; @@ -75,6 +76,7 @@ public Map getMap() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return languageHashMap.isEmpty(); diff --git a/src/main/java/com/yetanalytics/xapi/model/Result.java b/src/main/java/com/yetanalytics/xapi/model/Result.java index 8df9f04..a0dee7e 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Result.java +++ b/src/main/java/com/yetanalytics/xapi/model/Result.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -58,7 +59,10 @@ public void setExtensions(Extensions extensions) { this.extensions = extensions; } + // Validation + @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( diff --git a/src/main/java/com/yetanalytics/xapi/model/Score.java b/src/main/java/com/yetanalytics/xapi/model/Score.java index 043af7d..9a73eac 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Score.java +++ b/src/main/java/com/yetanalytics/xapi/model/Score.java @@ -2,6 +2,7 @@ import java.math.BigDecimal; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -52,6 +53,7 @@ public void setScaled(BigDecimal scaled) { // Validation + @JsonIgnore @AssertTrue public boolean isMinLessThanRaw() { if (raw != null && min != null) { @@ -61,6 +63,7 @@ public boolean isMinLessThanRaw() { } } + @JsonIgnore @AssertTrue public boolean isRawLessThanMax() { if (raw != null && max != null) { @@ -70,6 +73,7 @@ public boolean isRawLessThanMax() { } } + @JsonIgnore @AssertTrue public boolean isMinLessThanMax() { if (min != null && max != null) { @@ -80,6 +84,7 @@ public boolean isMinLessThanMax() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return raw == null && min == null && max == null && scaled == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/Statement.java b/src/main/java/com/yetanalytics/xapi/model/Statement.java index 1150e3d..af8421e 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Statement.java +++ b/src/main/java/com/yetanalytics/xapi/model/Statement.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -145,6 +146,7 @@ public void setAttachments(List attachments) { // Validation + @JsonIgnore @AssertTrue public boolean isValidVoidingStatement() { if (verb != null && verb.isVoiding()) { @@ -162,6 +164,7 @@ private boolean isObjectActivity() { } } + @JsonIgnore @AssertTrue public boolean isValidContextRevision() { return ( @@ -171,6 +174,7 @@ public boolean isValidContextRevision() { ); } + @JsonIgnore @AssertTrue public boolean isValidContextPlatform() { return ( @@ -181,6 +185,7 @@ public boolean isValidContextPlatform() { } // TODO: Somehow validate this on the Authority object itself + @JsonIgnore @AssertTrue public boolean isValidAuthority() { return authority == null || authority.isValidAuthority(); @@ -198,6 +203,7 @@ private boolean isValidSubStmt() { // TODO: Validate this on the SubStatement itself // (e.g. setting the objectType field) + @JsonIgnore @AssertTrue public boolean isValidSubStatement() { // System.out.println("Object is Statement: " + (object instanceof Statement)); @@ -211,6 +217,7 @@ public boolean isValidSubStatement() { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return ( diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java index 2044fdd..21eeb45 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementRef.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementRef.java @@ -2,6 +2,7 @@ import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -28,6 +29,7 @@ public void setId(UUID id) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return id == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java index e29efb5..8fb21c4 100644 --- a/src/main/java/com/yetanalytics/xapi/model/StatementResult.java +++ b/src/main/java/com/yetanalytics/xapi/model/StatementResult.java @@ -2,6 +2,7 @@ import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -36,6 +37,7 @@ public void setMore(String more) { } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return statements == null && more == null; diff --git a/src/main/java/com/yetanalytics/xapi/model/Verb.java b/src/main/java/com/yetanalytics/xapi/model/Verb.java index cd8c0ab..4da6035 100644 --- a/src/main/java/com/yetanalytics/xapi/model/Verb.java +++ b/src/main/java/com/yetanalytics/xapi/model/Verb.java @@ -1,5 +1,6 @@ package com.yetanalytics.xapi.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -39,11 +40,15 @@ public void setDisplay(LangMap display) { this.display = display; } + // Validation + + @JsonIgnore public boolean isVoiding() { return id == VOIDING_VERB_IRI; } @Override + @JsonIgnore @AssertFalse public boolean isEmpty() { return id == null && display == null;