You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2024/04/09 04:48:02 UTC
(causeway) branch v3 updated (7c7c8de477 -> 30b625b364)
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a change to branch v3
in repository https://gitbox.apache.org/repos/asf/causeway.git
from 7c7c8de477 Merge pull request #2345 from apache/dependabot/maven/v3/commons-io-commons-io-2.16.1
add 36deb9652d Bump commons-io:commons-io from 2.16.0 to 2.16.1
add ac01d958bb Merge pull request #2344 from apache/dependabot/maven/master/commons-io-commons-io-2.16.1
add 9c676ac4a1 CAUSEWAY-3718: adds Staff_Orig_IntegTest
add bdbef1770b CAUSEWAY-3718: reworks and extens integ tests for REST API (hilevel and lolevel)
add 86819e1f03 CAUSEWAY-3718: adds Legacy impl of BlobValueSemantics
add e4461ac56c CAUSEWAY-3718: JsonValueEncoderServiceDefault: fix for recover pojo from string
add 2c65b89d62 CAUSEWAY-3718: fixes a regression from earlier (weekend)
add 0659fbb1ca Merge remote-tracking branch 'origin/CAUSEWAY-3718'
new 30b625b364 Merge remote-tracking branch 'origin/master' into v3
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../value/semantics/ValueSemanticsAbstract.java | 1 -
core/metamodel/src/main/java/module-info.java | 1 +
.../metamodel/CausewayModuleCoreMetamodel.java | 2 +-
.../valuesemantics/BlobValueSemantics.java | 15 +-
.../client/ActionParameterListBuilder.java | 45 +++-
.../restfulobjects/client/RestfulClient.java | 2 +-
.../JsonValueEncoderServiceDefault.java | 33 ++-
viewers/restfulobjects/test/pom.xml | 271 ++++++++++----------
.../restfulobjects/test/domain/dom/Staff.java | 11 +
...IntegTest.can_create_staff_member.approved.json | 109 --------
.../test/scenarios/staff/Staff_IntegTest.java | 102 --------
...egTest.createStaffMemberWithPhoto.approved.json | 17 ++
...gTest.createStaffMemberWithPhoto2.approved.json | 17 ++
...teStaffMemberWithPhoto2_using_map.approved.json | 17 ++
...ateStaffMemberWithPhoto_using_map.approved.json | 17 ++
.../scenarios/staff/Staff_hilevel_IntegTest.java | 277 ++++++++++++++++++++
...gTest.createStaffMemberWithPhoto2.approved.json | 13 +
.../staff/Staff_lowlevel_v1_IntegTest.java | 280 +++++++++++++++++++++
...gTest.createStaffMemberWithPhoto2.approved.json | 17 ++
.../staff/Staff_lowlevel_v2_IntegTest.java | 181 +++++++++++++
.../src/test/resources/junit-platform.propertes | 2 +
21 files changed, 1063 insertions(+), 367 deletions(-)
delete mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_IntegTest.can_create_staff_member.approved.json
delete mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_IntegTest.java
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.createStaffMemberWithPhoto.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.createStaffMemberWithPhoto2.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.createStaffMemberWithPhoto2_using_map.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.createStaffMemberWithPhoto_using_map.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.java
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v1_IntegTest.createStaffMemberWithPhoto2.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v1_IntegTest.java
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v2_IntegTest.createStaffMemberWithPhoto2.approved.json
create mode 100644 viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v2_IntegTest.java
create mode 100644 viewers/restfulobjects/test/src/test/resources/junit-platform.propertes
(causeway) 01/01: Merge remote-tracking branch 'origin/master' into v3
Posted by ah...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v3
in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 30b625b364b6686580421f6ac34c0945be608f4f
Merge: 7c7c8de477 0659fbb1ca
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Apr 9 06:47:58 2024 +0200
Merge remote-tracking branch 'origin/master' into v3
.../value/semantics/ValueSemanticsAbstract.java | 1 -
core/metamodel/src/main/java/module-info.java | 1 +
.../metamodel/CausewayModuleCoreMetamodel.java | 2 +-
.../valuesemantics/BlobValueSemantics.java | 15 +-
.../client/ActionParameterListBuilder.java | 45 +++-
.../restfulobjects/client/RestfulClient.java | 2 +-
.../JsonValueEncoderServiceDefault.java | 33 ++-
viewers/restfulobjects/test/pom.xml | 271 ++++++++++----------
.../restfulobjects/test/domain/dom/Staff.java | 11 +
...IntegTest.can_create_staff_member.approved.json | 109 --------
.../test/scenarios/staff/Staff_IntegTest.java | 102 --------
...egTest.createStaffMemberWithPhoto.approved.json | 17 ++
...gTest.createStaffMemberWithPhoto2.approved.json | 17 ++
...teStaffMemberWithPhoto2_using_map.approved.json | 17 ++
...ateStaffMemberWithPhoto_using_map.approved.json | 17 ++
.../scenarios/staff/Staff_hilevel_IntegTest.java | 277 ++++++++++++++++++++
...gTest.createStaffMemberWithPhoto2.approved.json | 13 +
.../staff/Staff_lowlevel_v1_IntegTest.java | 280 +++++++++++++++++++++
...gTest.createStaffMemberWithPhoto2.approved.json | 17 ++
.../staff/Staff_lowlevel_v2_IntegTest.java | 181 +++++++++++++
.../src/test/resources/junit-platform.propertes | 2 +
21 files changed, 1063 insertions(+), 367 deletions(-)
diff --cc core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BlobValueSemantics.java
index a1a58fc94e,e128bb4002..84bf1f5345
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BlobValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BlobValueSemantics.java
@@@ -20,10 -20,12 +20,12 @@@ package org.apache.causeway.core.metamo
import java.util.function.UnaryOperator;
-import javax.annotation.Priority;
-import javax.inject.Named;
+import jakarta.annotation.Priority;
+import jakarta.inject.Named;
- import org.springframework.stereotype.Component;
+ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
import org.apache.causeway.applib.annotation.PriorityPrecedence;
import org.apache.causeway.applib.util.schema.CommonDtoUtils;
diff --cc viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/ActionParameterListBuilder.java
index 700b5a5820,21b69bb098..f9ffa579b4
--- a/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/ActionParameterListBuilder.java
+++ b/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/ActionParameterListBuilder.java
@@@ -22,8 -22,10 +22,10 @@@ import java.util.LinkedHashMap
import java.util.Map;
import java.util.stream.Collectors;
-import javax.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Entity;
+ import org.apache.causeway.applib.services.bookmark.Bookmark;
+
import org.springframework.lang.Nullable;
import org.apache.causeway.applib.util.schema.CommonDtoUtils;
diff --cc viewers/restfulobjects/test/pom.xml
index 6602899330,a6986d2ef6..ce4923c5cc
--- a/viewers/restfulobjects/test/pom.xml
+++ b/viewers/restfulobjects/test/pom.xml
@@@ -17,16 -17,18 +17,18 @@@
specific language governing permissions and limitations
under the License.
-->
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.causeway.viewer</groupId>
- <artifactId>causeway-viewer-restfulobjects</artifactId>
- <version>2.0.0-SNAPSHOT</version>
- </parent>
+ <parent>
+ <groupId>org.apache.causeway.viewer</groupId>
+ <artifactId>causeway-viewer-restfulobjects</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
- <artifactId>causeway-viewer-restfulobjects-test</artifactId>
+ <artifactId>causeway-viewer-restfulobjects-test</artifactId>
<name>Apache Causeway Viewer - RO (Test)</name>
diff --cc viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.java
index 0000000000,b1e02c753f..e4b9c5cd8a
mode 000000,100644..100644
--- a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.java
+++ b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_hilevel_IntegTest.java
@@@ -1,0 -1,278 +1,277 @@@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ package org.apache.causeway.viewer.restfulobjects.test.scenarios.staff;
+
-import javax.ws.rs.core.Response;
++import java.util.Map;
+
-import org.apache.causeway.applib.services.bookmark.Bookmark;
++import jakarta.ws.rs.core.Response;
+
+ import org.approvaltests.Approvals;
+ import org.approvaltests.reporters.DiffReporter;
+ import org.approvaltests.reporters.UseReporter;
+ import org.junit.jupiter.api.Test;
+
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import org.springframework.transaction.annotation.Propagation;
+
++import org.apache.causeway.applib.services.bookmark.Bookmark;
+ import org.apache.causeway.applib.value.Blob;
+ import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
+ import org.apache.causeway.commons.io.DataSource;
+ import org.apache.causeway.viewer.restfulobjects.test.domain.dom.Department;
+ import org.apache.causeway.viewer.restfulobjects.test.scenarios.Abstract_IntegTest;
+
+ import lombok.SneakyThrows;
+ import lombok.val;
+
-import java.util.Map;
-
+ class Staff_hilevel_IntegTest extends Abstract_IntegTest {
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ final Blob photo = readFileAsBlob("StaffMember-photo-Bar.pdf");
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto/invoke");
+
+ /*
+ * String name,
+ * Department.SecondaryKey departmentSecondaryKey,
+ * Blob photo
+ */
+ var args = restfulClient.arguments()
+ .addActionParameter("name", staffName)
+ .addActionParameter("departmentSecondaryKey", Department.SecondaryKey.class, new Department.SecondaryKey("Classics"))
+ .addActionParameter("photo", photo)
+ .build();
+
+ Approvals.verify(args.getEntity(), jsonOptions());
+
+ // when
+ val response = requestBuilder.post(args);
+
+ // then
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+ val entity = response.readEntity(String.class);
+ assertThat(response)
+ .extracting(Response::getStatus)
+ .isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto_using_map() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ final Blob photo = readFileAsBlob("StaffMember-photo-Bar.pdf");
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto/invoke");
+
+ var args = restfulClient.arguments()
+ .addActionParameter("name", staffName)
+ .addActionParameter("departmentSecondaryKey", Map.of("name", "Classics"))
+ .addActionParameter("photo", photo)
+ .build();
+
+ Approvals.verify(args.getEntity(), jsonOptions());
+
+ // when
+ val response = requestBuilder.post(args);
+
+ // then
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+ val entity = response.readEntity(String.class);
+ assertThat(response)
+ .extracting(Response::getStatus)
+ .isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto2() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ // and given
+ final var departmentName = "Classics";
+ final var departmentBookmark = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = departmentRepository.findByName(departmentName);
+ return bookmarkService.bookmarkFor(staffMember).orElseThrow();
+ }).valueAsNonNullElseFail();
+
+ // and given
+ final Blob photo = readFileAsBlob("StaffMember-photo-Bar.pdf");
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto2/invoke");
+
+ var args = restfulClient.arguments()
+ .addActionParameter("name", staffName)
+ .addActionParameter("department", departmentBookmark)
+ .addActionParameter("photo", photo)
+ .build();
+
+ Approvals.verify(args.getEntity(), jsonOptions());
+
+ // when
+ val response = requestBuilder.post(args);
+
+ // then
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+ val entity = response.readEntity(String.class);
+ assertThat(response)
+ .extracting(Response::getStatus)
+ .isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto2_using_map() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ // and given
+ final var departmentName = "Classics";
+ final var departmentBookmark = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = departmentRepository.findByName(departmentName);
+ return bookmarkService.bookmarkFor(staffMember).orElseThrow();
+ }).valueAsNonNullElseFail();
+
+ // and given
+ final Blob photo = readFileAsBlob("StaffMember-photo-Bar.pdf");
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto2/invoke");
+
+ /*
+ * String name,
+ * Department.SecondaryKey departmentSecondaryKey,
+ * Blob photo
+ */
+ var args = restfulClient.arguments()
+ .addActionParameter("name", staffName)
+ .addActionParameter("department", Map.of("href", asAbsoluteHref(departmentBookmark)))
+ .addActionParameter("photo", photo)
+ .build();
+
+ Approvals.verify(args.getEntity(), jsonOptions());
+
+ // when
+ val response = requestBuilder.post(args);
+
+ // then
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+ val entity = response.readEntity(String.class);
+ assertThat(response)
+ .extracting(Response::getStatus)
+ .isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
+
+ private Blob readFileAsBlob(final String fileName) {
+ var bytes = DataSource.ofResource(Abstract_IntegTest.class, fileName)
+ .bytes();
+ return Blob.of(fileName, CommonMimeType.PDF, bytes);
+ }
+
- private String asAbsoluteHref(Bookmark bookmark) {
++ private String asAbsoluteHref(final Bookmark bookmark) {
+ return String.format("%s%s", restfulClient.getConfig().getRestfulBaseUrl(), asRelativeHref(bookmark));
+ }
+
- private String asRelativeHref(Bookmark bookmark) {
++ private String asRelativeHref(final Bookmark bookmark) {
+ return String.format("objects/%s/%s", bookmark.getLogicalTypeName(), bookmark.getIdentifier());
+ }
+
+
+ }
+
diff --cc viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v1_IntegTest.java
index 0000000000,399178c91f..485bcff32c
mode 000000,100644..100644
--- a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v1_IntegTest.java
+++ b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v1_IntegTest.java
@@@ -1,0 -1,279 +1,280 @@@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ package org.apache.causeway.viewer.restfulobjects.test.scenarios.staff;
+
+ import java.io.IOException;
+ import java.net.URISyntaxException;
+ import java.nio.charset.StandardCharsets;
+ import java.util.Base64;
+
-import javax.activation.MimeType;
-import javax.activation.MimeTypeParseException;
-import javax.annotation.Priority;
-import javax.inject.Named;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.core.Response;
-
-import com.google.common.io.Resources;
++import jakarta.activation.MimeType;
++import jakarta.activation.MimeTypeParseException;
++import jakarta.annotation.Priority;
++import jakarta.inject.Named;
++import jakarta.ws.rs.client.Entity;
++import jakarta.ws.rs.client.Invocation;
++import jakarta.ws.rs.core.Response;
++
+ import com.google.gson.GsonBuilder;
+
+ import org.approvaltests.Approvals;
+ import org.approvaltests.reporters.DiffReporter;
+ import org.approvaltests.reporters.UseReporter;
+ import org.junit.jupiter.api.BeforeEach;
+ import org.junit.jupiter.api.Order;
+ import org.junit.jupiter.api.Test;
+
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import org.springframework.context.annotation.Import;
+ import org.springframework.stereotype.Component;
+ import org.springframework.test.annotation.DirtiesContext;
+ import org.springframework.transaction.annotation.Propagation;
+
+ import org.apache.causeway.applib.annotation.PriorityPrecedence;
+ import org.apache.causeway.applib.services.bookmark.Bookmark;
+ import org.apache.causeway.applib.value.Blob;
+ import org.apache.causeway.applib.value.NamedWithMimeType;
+ import org.apache.causeway.applib.value.semantics.Renderer;
+ import org.apache.causeway.applib.value.semantics.ValueDecomposition;
+ import org.apache.causeway.applib.value.semantics.ValueSemanticsProvider;
+ import org.apache.causeway.commons.collections.Can;
+ import org.apache.causeway.commons.internal.base._Bytes;
+ import org.apache.causeway.commons.internal.base._Strings;
++import org.apache.causeway.commons.io.DataSource;
+ import org.apache.causeway.core.metamodel.valuesemantics.BlobValueSemantics;
+ import org.apache.causeway.schema.common.v2.ValueType;
+ import org.apache.causeway.viewer.restfulobjects.test.scenarios.Abstract_IntegTest;
+
+ import lombok.Getter;
+ import lombok.SneakyThrows;
+ import lombok.val;
+
+
+ @Order(value = Integer.MAX_VALUE) // last
+ @DirtiesContext
+ @Import({Staff_lowlevel_v1_IntegTest.BlobValueSemanticsV1LegacyEncoding.class})
+ public class Staff_lowlevel_v1_IntegTest extends Abstract_IntegTest {
+
+ private GsonBuilder gsonBuilder;
+
+ @BeforeEach
+ void setup() {
+ gsonBuilder = new GsonBuilder();
+ }
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto2() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ // and given
+ final var departmentName = "Classics";
+ final var departmentBookmark = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = departmentRepository.findByName(departmentName);
+ return bookmarkService.bookmarkFor(staffMember).orElseThrow();
+ }).valueAsNonNullElseFail();
+
+ String departmentHref = asRelativeHref(departmentBookmark);
+ Invocation.Builder departmentRequest = restfulClient.request(departmentHref);
+ Response departmentResponse = departmentRequest.get();
+ assertThat(departmentResponse.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+
+ // and given
+ final var photoEncoded = readFileAndEncodeAsBlob("StaffMember-photo-Bar.pdf");
+
+ // when create request
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto2/invoke");
+
+ final var body = new Body(staffName, asAbsoluteHref(departmentBookmark), photoEncoded);
+ final var bodyJson = gsonBuilder.create().toJson(body);
+
+ // then
+ Approvals.verify(bodyJson, jsonOptions());
+
+ // and when send request
+ val response = requestBuilder.post(Entity.entity(bodyJson, "application/json"));
+
+ // then
+ val entity = response.readEntity(String.class);
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
+ private String asAbsoluteHref(final Bookmark bookmark) {
+ return String.format("%s%s", restfulClient.getConfig().getRestfulBaseUrl(), asRelativeHref(bookmark));
+ }
+
+ private String asRelativeHref(final Bookmark bookmark) {
+ return String.format("objects/%s/%s", bookmark.getLogicalTypeName(), bookmark.getIdentifier());
+ }
+
+ private String readFileAndEncodeAsBlob(final String fileName) throws IOException, URISyntaxException {
- byte[] bytes = Resources.toByteArray(Resources.getResource(Abstract_IntegTest.class, fileName));
++ var bytes = DataSource.ofResource(Abstract_IntegTest.class, fileName)
++ .bytes();
+ String photoEncoded = encodePdf(fileName, bytes);
+ return photoEncoded;
+ }
+
+ private String encodePdf(final String fileName, final byte[] pdfBytes) throws URISyntaxException {
+ final String pdfBytesEncoded = Base64.getEncoder().encodeToString(pdfBytes);
+ final String encodedBlob = String.format("%s:%s:%s", fileName, "application/pdf", pdfBytesEncoded);
+ return encodedBlob;
+ }
+
+ @Getter
+ static class Body {
+
+ /**
+ * @param nameValue
+ * @param departmentHrefValue
+ * @param blobValue - is the Blob encoded format: "filename.pdf:application/pdf:pdfBytesBase64Encoded"
+ */
+ Body(final String nameValue, final String departmentHrefValue, final String blobValue) {
+ photo = new Blob(blobValue);
+ name = new Name(nameValue);
+ department = new Department(new Department.Value(departmentHrefValue));
+ }
+
+ private Name name;
+ private Department department;
+ private Blob photo;
+
+ @lombok.Value
+ static class Name {
+ private String value;
+ }
+
+ @lombok.Value
+ static class Department {
+ private Value value;
+
+ @lombok.Value
+ static class Value {
+ private String href;
+ }
+
+ }
+
+ @lombok.Value
+ static class Blob {
+ private String value;
+ }
+ }
+
+ @Component
+ @Named("causeway.metamodel.value.BlobValueSemantics")
+ @Priority(PriorityPrecedence.EARLY)
+ public static class BlobValueSemanticsV1LegacyEncoding
+ extends BlobValueSemantics
+ implements
+ Renderer<Blob> {
+
+ public BlobValueSemanticsV1LegacyEncoding(){
+ }
+
+ @Override
+ public Class<Blob> getCorrespondingClass() {
+ return Blob.class;
+ }
+
+ @Override
+ public ValueType getSchemaValueType() {
+ return ValueType.STRING;
+ }
+
+ // -- COMPOSER
+
+ @Override
+ public ValueDecomposition decompose(final Blob value) {
+ return decomposeAsString(value, this::toEncodedString, () -> null);
+ }
+
+ @Override
+ public Blob compose(final ValueDecomposition decomposition) {
+ return composeFromString(decomposition, this::fromEncodedString, ()->null);
+ }
+
+ // RENDERER
+
+ @Override
+ public String titlePresentation(final ValueSemanticsProvider.Context context, final Blob value) {
+ return renderTitle(value, Blob::getName);
+ }
+
+ @Override
+ public String htmlPresentation(final ValueSemanticsProvider.Context context, final Blob value) {
+ return renderHtml(value, Blob::getName);
+ }
+
+ private String toEncodedString(final Blob blob) {
+ return blob.getName() + ":" + blob.getMimeType().getBaseType() + ":" +
+ _Strings.ofBytes(_Bytes.encodeToBase64(Base64.getEncoder(), blob.getBytes()), StandardCharsets.UTF_8);
+ }
+
+ private Blob fromEncodedString(final String data) {
+ final int colonIdx = data.indexOf(':');
+ final String name = data.substring(0, colonIdx);
+ final int colon2Idx = data.indexOf(":", colonIdx+1);
+ final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
+ final String payload = data.substring(colon2Idx+1);
+ final byte[] bytes = _Bytes.decodeBase64(Base64.getDecoder(), payload.getBytes(StandardCharsets.UTF_8));
+ try {
+ return new Blob(name, new MimeType(mimeTypeBase), bytes);
+ } catch (MimeTypeParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // -- EXAMPLES
+
+ @Override
+ public Can<Blob> getExamples() {
+ return Can.of(
+ Blob.of("a Blob", NamedWithMimeType.CommonMimeType.BIN, new byte[] {1, 2, 3}),
+ Blob.of("another Blob", NamedWithMimeType.CommonMimeType.BIN, new byte[] {3, 4}));
+ }
+
+ }
+
+
+ }
+
+
+
+
diff --cc viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v2_IntegTest.java
index 0000000000,26b6eeb8a1..146a186e49
mode 000000,100644..100644
--- a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v2_IntegTest.java
+++ b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_lowlevel_v2_IntegTest.java
@@@ -1,0 -1,181 +1,181 @@@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ package org.apache.causeway.viewer.restfulobjects.test.scenarios.staff;
+
+ import java.io.IOException;
+ import java.util.Base64;
+
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.core.Response;
++import jakarta.ws.rs.client.Entity;
++import jakarta.ws.rs.client.Invocation;
++import jakarta.ws.rs.core.Response;
+
-import com.google.common.io.Resources;
+ import com.google.gson.GsonBuilder;
+
-import org.apache.causeway.applib.value.Blob;
-
+ import org.approvaltests.Approvals;
+ import org.approvaltests.reporters.DiffReporter;
+ import org.approvaltests.reporters.UseReporter;
+ import org.junit.jupiter.api.BeforeEach;
+ import org.junit.jupiter.api.Test;
+
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import org.springframework.transaction.annotation.Propagation;
+
+ import org.apache.causeway.applib.services.bookmark.Bookmark;
++import org.apache.causeway.applib.value.Blob;
++import org.apache.causeway.commons.io.DataSource;
+ import org.apache.causeway.viewer.restfulobjects.test.scenarios.Abstract_IntegTest;
+
+ import lombok.Getter;
+ import lombok.SneakyThrows;
+ import lombok.val;
+
+ public class Staff_lowlevel_v2_IntegTest extends Abstract_IntegTest {
+
+ private GsonBuilder gsonBuilder;
+
+ @BeforeEach
+ void setup() {
+ gsonBuilder = new GsonBuilder();
+ }
+
+ @SneakyThrows
+ @Test
+ @UseReporter(DiffReporter.class)
+ public void createStaffMemberWithPhoto2() {
+
+ // given
+ final var staffName = "Fred Smith";
+
+ final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+
+ assertThat(bookmarkBeforeIfAny).isEmpty();
+
+ // and given
+ final var departmentName = "Classics";
+ final var departmentBookmark = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = departmentRepository.findByName(departmentName);
+ return bookmarkService.bookmarkFor(staffMember).orElseThrow();
+ }).valueAsNonNullElseFail();
+
+ String departmentHref = asRelativeHref(departmentBookmark);
+ Invocation.Builder departmentRequest = restfulClient.request(departmentHref);
+ Response departmentResponse = departmentRequest.get();
+ assertThat(departmentResponse.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+
+ // and given
+ final var photoEncoded = readFileAsBlob("StaffMember-photo-Bar.pdf");
+
+ // when create request
+ final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto2/invoke");
+
+ final var body = new Body(staffName, asAbsoluteHref(departmentBookmark), photoEncoded);
+ final var bodyJson = gsonBuilder.create().toJson(body);
+
+ // then
+ Approvals.verify(bodyJson, jsonOptions());
+
+ // and when send request
+ val response = requestBuilder.post(Entity.entity(bodyJson, "application/json"));
+
+ // then
+ val entity = response.readEntity(String.class);
+ assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL);
+ assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+
+ // and also json response
+
+ // and also object is created in database
+ final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> {
+ final var staffMember = staffMemberRepository.findByName(staffName);
+ return bookmarkService.bookmarkFor(staffMember);
+ }).valueAsNonNullElseFail();
+ assertThat(bookmarkAfterIfAny).isNotEmpty();
+ }
+
- private String asAbsoluteHref(Bookmark bookmark) {
++ private String asAbsoluteHref(final Bookmark bookmark) {
+ return String.format("%s%s", restfulClient.getConfig().getRestfulBaseUrl(), asRelativeHref(bookmark));
+ }
+
- private String asRelativeHref(Bookmark bookmark) {
++ private String asRelativeHref(final Bookmark bookmark) {
+ return String.format("objects/%s/%s", bookmark.getLogicalTypeName(), bookmark.getIdentifier());
+ }
+
- private Blob readFileAsBlob(String fileName) throws IOException {
- byte[] bytes = Resources.toByteArray(Resources.getResource(Abstract_IntegTest.class, fileName));
++ private Blob readFileAsBlob(final String fileName) throws IOException {
++ var bytes = DataSource.ofResource(Abstract_IntegTest.class, fileName)
++ .bytes();
+ return new Blob(fileName, "application/pdf", bytes);
+ }
+
+
+ @Getter
+ static class Body {
+
+ /**
+ * @param nameValue
+ * @param departmentHrefValue
+ * @param blob - is the Blob to be formatted
+ */
- Body(String nameValue, String departmentHrefValue, org.apache.causeway.applib.value.Blob blob) {
++ Body(final String nameValue, final String departmentHrefValue, final org.apache.causeway.applib.value.Blob blob) {
+ name = new Name(nameValue);
+ department = new Department(new Department.Value(departmentHrefValue));
+ photo = new Blob(new Blob.Value(blob.getName(), blob.getMimeType().toString(), Base64.getEncoder().encodeToString(blob.getBytes())));
+ }
+
+ private Name name;
+ private Department department;
+ private Blob photo;
+
+ @lombok.Value
+ static class Name {
+ private String value;
+ }
+
+ @lombok.Value
+ static class Department {
+ private Value value;
+
+ @lombok.Value
+ static class Value {
+ private String href;
+ }
+
+ }
+
+
+ @lombok.Value
+ static class Blob {
+ private Value value;
+
+ @lombok.Value
+ static class Value {
+ private String name;
+ private String mimeType;
+ private String bytes;
+ }
+ }
+
+ }
+
+ }
+
+