From 7f53578b539f2b2a60764a9717478a298f730f07 Mon Sep 17 00:00:00 2001
From: Thomas Turrell-Croft
Date: Tue, 23 May 2023 16:25:45 +0100
Subject: [PATCH 1/4] Update eclipse settings
---
.../xapi-server/.settings/org.eclipse.jdt.core.prefs | 10 +++++++++-
xapi-client/.settings/org.eclipse.jdt.core.prefs | 10 +++++++++-
xapi-model/.settings/org.eclipse.jdt.core.prefs | 3 ++-
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/samples/xapi-server/.settings/org.eclipse.jdt.core.prefs b/samples/xapi-server/.settings/org.eclipse.jdt.core.prefs
index 89df520e..e70d5c24 100644
--- a/samples/xapi-server/.settings/org.eclipse.jdt.core.prefs
+++ b/samples/xapi-server/.settings/org.eclipse.jdt.core.prefs
@@ -1,11 +1,19 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.springframework.lang.NonNull
+org.eclipse.jdt.core.compiler.annotation.nullable=org.springframework.lang.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
-org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.processAnnotations=disabled
+org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
diff --git a/xapi-client/.settings/org.eclipse.jdt.core.prefs b/xapi-client/.settings/org.eclipse.jdt.core.prefs
index 89df520e..f5301f16 100644
--- a/xapi-client/.settings/org.eclipse.jdt.core.prefs
+++ b/xapi-client/.settings/org.eclipse.jdt.core.prefs
@@ -1,11 +1,19 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.springframework.lang.NonNull
+org.eclipse.jdt.core.compiler.annotation.nullable=org.springframework.lang.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
-org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.processAnnotations=enabled
+org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
diff --git a/xapi-model/.settings/org.eclipse.jdt.core.prefs b/xapi-model/.settings/org.eclipse.jdt.core.prefs
index 89df520e..a4cb91c9 100644
--- a/xapi-model/.settings/org.eclipse.jdt.core.prefs
+++ b/xapi-model/.settings/org.eclipse.jdt.core.prefs
@@ -5,7 +5,8 @@ org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
-org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.processAnnotations=enabled
+org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
From 8dda127f80a6d40d2592340b431f9ff82271b888 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?=
Date: Wed, 24 May 2023 09:22:37 +0100
Subject: [PATCH 2/4] resolve warnings
---
.../client/MissingResponseBodyException.java | 18 ++++++++++++++++++
.../dev/learning/xapi/client/XapiClient.java | 9 ++++++++-
.../xapi/client/XapiClientMultipartTests.java | 2 ++
.../StrictObjectTypeResolverBuilder.java | 2 +-
4 files changed, 29 insertions(+), 2 deletions(-)
create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/MissingResponseBodyException.java
diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/MissingResponseBodyException.java b/xapi-client/src/main/java/dev/learning/xapi/client/MissingResponseBodyException.java
new file mode 100644
index 00000000..8e9af431
--- /dev/null
+++ b/xapi-client/src/main/java/dev/learning/xapi/client/MissingResponseBodyException.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ */
+
+package dev.learning.xapi.client;
+
+/**
+ *
+ * MissingResponseBodyException class.
+ *
+ *
+ * @author István Rátkai (Selindek)
+ */
+public class MissingResponseBodyException extends RuntimeException {
+
+ private static final long serialVersionUID = -5731953477307546047L;
+
+}
diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java
index 7f7466a3..e3fb9812 100644
--- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java
+++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -123,6 +124,8 @@ public Mono> getStatement(
*
*
* @return the ResponseEntity
+ *
+ * @throws MissingResponseBodyException if the response body is missing
*/
public Mono> postStatement(PostStatementRequest request) {
@@ -140,7 +143,8 @@ public Mono> postStatement(PostStatementRequest request) {
.toEntity(LIST_UUID_TYPE)
- .map(i -> ResponseEntity.ok().headers(i.getHeaders()).body(i.getBody().get(0)));
+ .map(i -> ResponseEntity.ok().headers(i.getHeaders()).body(Optional.ofNullable(i.getBody())
+ .map(l -> l.get(0)).orElseThrow(MissingResponseBodyException::new)));
}
@@ -1432,6 +1436,9 @@ public Stream toStream() {
private void init(ResponseEntity response) {
final var statementResult = response.getBody();
+ if (statementResult == null) {
+ throw new MissingResponseBodyException();
+ }
more = statementResult.hasMore() ? statementResult.getMore() : null;
final var s = statementResult.getStatements();
statements = s == null ? Collections.emptyIterator() : s.iterator();
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientMultipartTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientMultipartTests.java
index 84e90bcf..5a2ee097 100644
--- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientMultipartTests.java
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientMultipartTests.java
@@ -326,6 +326,7 @@ void whenPostingStatementsWithTimestampAndAttachmentThenNoExceptionIsThrown()
}
+ @SuppressWarnings("null")
@Test
void whenGettingStatementWithAttachmentThenResponseIsExpected() throws InterruptedException {
@@ -367,6 +368,7 @@ void whenGettingStatementWithAttachmentThenResponseIsExpected() throws Interrupt
"Statement(id=183aabbe-ef9e-49c9-82a3-16ce5135b25b, actor=Agent(super=Actor(name=A N Other, mbox=mailto:another@example.com, mboxSha1sum=null, openid=null, account=null)), verb=Verb(id=http://adlnet.gov/expapi/verbs/attempted, display={und=attempted}), object=Activity(id=https://example.com/activity/simplestatement, definition=ActivityDefinition(name={en=Simple Statement}, description=null, type=null, moreInfo=null, interactionType=null, correctResponsesPattern=null, choices=null, scale=null, source=null, target=null, steps=null, extensions=null)), result=null, context=null, timestamp=2023-03-29T12:42:27.923571Z, stored=2023-03-29T12:42:27.923571Z, authority=Agent(super=Actor(name=null, mbox=null, mboxSha1sum=null, openid=null, account=Account(homePage=http://localhost, name=admin))), version=null, attachments=[Attachment(usageType=http://adlnet.gov/expapi/attachments/code, display={en=binary attachment}, description=null, contentType=application/octet-stream, length=6, sha2=0ff3c6749b3eeaae17254fdf0e2de1f32b21c592f474bf39b62b398e8a787eef, fileUrl=null, content=[64, 65, 66, 67, 68, 69]), Attachment(usageType=http://adlnet.gov/expapi/attachments/text, display={en=text attachment}, description=null, contentType=text/plain, length=17, sha2=b154d3fd46a5068da42ba05a8b9c971688ab5a57eb5c3a0e50a23c42a86786e5, fileUrl=null, content=[83, 105, 109, 112, 108, 101, 32, 97, 116, 116, 97, 99, 104, 109, 101, 110, 116])])"));
}
+ @SuppressWarnings("null")
@Test
void whenGettingStatementsWithAttachmentsThenResponseIsExpected() throws InterruptedException {
diff --git a/xapi-model/src/main/java/dev/learning/xapi/jackson/StrictObjectTypeResolverBuilder.java b/xapi-model/src/main/java/dev/learning/xapi/jackson/StrictObjectTypeResolverBuilder.java
index 835919c3..d05e2a58 100644
--- a/xapi-model/src/main/java/dev/learning/xapi/jackson/StrictObjectTypeResolverBuilder.java
+++ b/xapi-model/src/main/java/dev/learning/xapi/jackson/StrictObjectTypeResolverBuilder.java
@@ -50,7 +50,7 @@ public static class StrictObjectTypePropertyDeserializer extends AsPropertyTypeD
public StrictObjectTypePropertyDeserializer(JavaType baseType, TypeIdResolver idRes,
String typeProperty, boolean typeIdVisible, JavaType defaultImpl, As includeAs) {
- super(baseType, idRes, typeProperty, typeIdVisible, defaultImpl, includeAs);
+ super(baseType, idRes, typeProperty, typeIdVisible, defaultImpl, includeAs, true);
}
public StrictObjectTypePropertyDeserializer(AsPropertyTypeDeserializer src,
From 293a11afaa1fc51cda66d8ae91713e224f4f1e6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?=
Date: Wed, 24 May 2023 15:52:33 +0100
Subject: [PATCH 3/4] add tests
---
.../learning/xapi/client/XapiClientTests.java | 69 +++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
index 85f4252d..c0a0430f 100644
--- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
@@ -36,6 +36,8 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientResponseException.BadRequest;
+import org.springframework.web.reactive.function.client.WebClientResponseException.InternalServerError;
/**
* XapiClient Tests.
@@ -379,6 +381,73 @@ void whenPostingStatementThenContentTypeHeaderIsApplicationJson() throws Interru
assertThat(recordedRequest.getHeader("content-type"), is("application/json"));
}
+ @Test
+ void givenApiResponseIsEmptyWhenPostingStatementThenMissingResponseBodyExceptionIsThrown() {
+
+ // Given Api Response Is Empty
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK").setHeader("Content-Type",
+ "application/json"));
+
+ // When Posting Statement
+ // Then MissingResponseBodyException Is Thrown
+ assertThrows(MissingResponseBodyException.class,
+ () -> client
+ .postStatement(
+ r -> r.statement(
+ s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block());
+
+ }
+
+ @Test
+ void givenApiResponseIsBadRequestWhenPostingStatementThenBadRequestIsThrown() {
+
+ // Given Api Response Is Bad Request
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 400 Bad Request"));
+
+ // When Posting Statement
+ // Then BadRequest Is Thrown
+ assertThrows(BadRequest.class,
+ () -> client
+ .postStatement(
+ r -> r.statement(
+ s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block());
+
+ }
+
+ @Test
+ void givenApiResponseIsInternalServerErrorWhenPostingStatementThenInternalServerErrorIsThrown() {
+
+ // Given Api Response Is Internal Server Error
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 500 Internal Server Error"));
+
+ // When Posting Statement
+ // Then InternalServerError Is Thrown
+ assertThrows(InternalServerError.class,
+ () -> client
+ .postStatement(
+ r -> r.statement(
+ s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block());
+
+ }
+
// Posting a Signed Statement
@Test
From 3ae642b0b772b915a046f8de64019f4dbea382da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?=
Date: Thu, 25 May 2023 09:34:13 +0100
Subject: [PATCH 4/4] fsi
---
.../learning/xapi/client/XapiClientTests.java | 54 +++++++++----------
1 file changed, 24 insertions(+), 30 deletions(-)
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
index c0a0430f..969ec96a 100644
--- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
@@ -389,18 +389,16 @@ void givenApiResponseIsEmptyWhenPostingStatementThenMissingResponseBodyException
"application/json"));
// When Posting Statement
- // Then MissingResponseBodyException Is Thrown
- assertThrows(MissingResponseBodyException.class,
- () -> client
- .postStatement(
- r -> r.statement(
- s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+ final var response = client.postStatement(r -> r
+ .statement(s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
- .verb(Verb.ATTEMPTED)
+ .verb(Verb.ATTEMPTED)
- .activityObject(o -> o.id("https://example.com/activity/simplestatement")
- .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
- .block());
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))));
+
+ // Then MissingResponseBodyException Is Thrown
+ assertThrows(MissingResponseBodyException.class, () -> response.block());
}
@@ -411,18 +409,16 @@ void givenApiResponseIsBadRequestWhenPostingStatementThenBadRequestIsThrown() {
mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 400 Bad Request"));
// When Posting Statement
- // Then BadRequest Is Thrown
- assertThrows(BadRequest.class,
- () -> client
- .postStatement(
- r -> r.statement(
- s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+ final var response = client.postStatement(r -> r
+ .statement(s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
- .verb(Verb.ATTEMPTED)
+ .verb(Verb.ATTEMPTED)
- .activityObject(o -> o.id("https://example.com/activity/simplestatement")
- .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
- .block());
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))));
+
+ // Then BadRequest Is Thrown
+ assertThrows(BadRequest.class, () -> response.block());
}
@@ -433,18 +429,16 @@ void givenApiResponseIsInternalServerErrorWhenPostingStatementThenInternalServer
mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 500 Internal Server Error"));
// When Posting Statement
- // Then InternalServerError Is Thrown
- assertThrows(InternalServerError.class,
- () -> client
- .postStatement(
- r -> r.statement(
- s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+ final var response = client.postStatement(r -> r
+ .statement(s -> s.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
- .verb(Verb.ATTEMPTED)
+ .verb(Verb.ATTEMPTED)
- .activityObject(o -> o.id("https://example.com/activity/simplestatement")
- .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
- .block());
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))));
+
+ // Then InternalServerError Is Thrown
+ assertThrows(InternalServerError.class, () -> response.block());
}