This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 6613eee170 TODO-242: Add petstore @Remote typed-client demo + 
Config/SVL showcase.
6613eee170 is described below

commit 6613eee170305dc39706c77422fa583ae15b8a56
Author: James Bognar <[email protected]>
AuthorDate: Wed Jul 15 12:14:51 2026 -0400

    TODO-242: Add petstore @Remote typed-client demo + Config/SVL showcase.
    
    Phase 9 - PetStoreClient @Remote interface (juneau-petstore-core) mirroring
    PetStoreResource's pet CRUD surface, plus a client-consuming Jetty container
    test driving a genuine HTTP round-trip via 
RestClient.remote(PetStoreClient).
    Phase 10 - [Petstore] cfg section + $C{} SVL substitution in the root
    router's @HtmlDocConfig header.
    
    Also resolves 3 Eclipse warnings surfaced along the way: a 
resource-suppression
    idiom on the client test's try-with-resources, {@code} demotion of an
    off-classpath javadoc @link, and an unused import in PetHtmlResource.
    
    Co-authored-by: Cursor <[email protected]>
---
 .../juneau/petstore/client/PetStoreClient.java     | 67 ++++++++++++++++
 .../juneau/petstore/client/package-info.java       | 25 ++++++
 .../juneau/petstore/rest/PetHtmlResource.java      |  1 -
 .../juneau-petstore-jetty.cfg                      | 15 ++++
 juneau-petstore/juneau-petstore-jetty/pom.xml      |  7 ++
 .../juneau/petstore/jetty/RootResources.java       | 10 +++
 .../juneau/petstore/jetty/PetStoreClient_Test.java | 92 ++++++++++++++++++++++
 .../juneau/petstore/jetty/PetstoreJetty_Test.java  | 12 +++
 8 files changed, 228 insertions(+), 1 deletion(-)

diff --git 
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/PetStoreClient.java
 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/PetStoreClient.java
new file mode 100644
index 0000000000..b0433f1141
--- /dev/null
+++ 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/PetStoreClient.java
@@ -0,0 +1,67 @@
+/*
+ * 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.juneau.petstore.client;
+
+import java.util.*;
+
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.remote.*;
+import org.apache.juneau.petstore.dto.*;
+
+/**
+ * Typed client view of the petstore pet CRUD surface, consumed via {@code 
org.apache.juneau.rest.client.RestClient#remote(Class)}.
+ *
+ * <p>
+ * Mirrors the pet endpoints of {@link 
org.apache.juneau.petstore.rest.PetStoreResource} (mounted at
+ * {@code /petstore} in both the Jetty and Spring Boot deployments). 
Demonstrates Juneau's REST client consuming
+ * a REST resource written with Juneau's REST server — the client interface 
and the server resource live in
+ * different modules but share nothing but the wire protocol and the {@link 
Pet} DTO.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/RestProxies";>REST Proxy Basics</a>
+ *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauPetstore";>juneau-petstore</a>
+ * </ul>
+ */
+@Remote(path="/petstore")
+public interface PetStoreClient {
+
+       /**
+        * Lists all pets.
+        *
+        * @return All pets.
+        */
+       @RemoteGet("/pets")
+       List<Pet> getPets();
+
+       /**
+        * Retrieves a pet by ID.
+        *
+        * @param id The pet ID.
+        * @return The pet.
+        */
+       @RemoteGet("/pets/{id}")
+       Pet getPet(@Path("id") long id);
+
+       /**
+        * Creates a new pet.
+        *
+        * @param pet The pet to create.
+        * @return The created pet (with assigned ID).
+        */
+       @RemotePost("/pets")
+       Pet addPet(@Content Pet pet);
+}
diff --git 
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/package-info.java
 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/package-info.java
new file mode 100644
index 0000000000..5ba0e81796
--- /dev/null
+++ 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/client/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/**
+ * Typed {@code @Remote} client view of the petstore API.
+ *
+ * <p>
+ * Deployment-agnostic (like {@code org.apache.juneau.petstore.rest}) so it 
can be consumed by tests in either the
+ * {@code juneau-petstore-jetty} or {@code juneau-petstore-springboot} 
deployment modules via
+ * {@link org.apache.juneau.rest.client.RestClient#remote(Class)}.
+ */
+package org.apache.juneau.petstore.client;
diff --git 
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetHtmlResource.java
 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetHtmlResource.java
index 6a0971af32..1030a3f56b 100644
--- 
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetHtmlResource.java
+++ 
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetHtmlResource.java
@@ -23,7 +23,6 @@ import java.util.*;
 import org.apache.juneau.bean.html5.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.response.*;
-import org.apache.juneau.petstore.dto.*;
 import org.apache.juneau.petstore.service.*;
 import org.apache.juneau.rest.server.*;
 import org.apache.juneau.rest.server.beans.*;
diff --git a/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg 
b/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
index d09858b04a..31fc1518d2 100644
--- a/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
+++ b/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
@@ -118,3 +118,18 @@ RestContext.disableClasspathResourceCaching.b = true
 
#=======================================================================================================================
 [Source]
 gitHub = 
https://github.com/apache/juneau/blob/master/juneau-petstore/juneau-petstore-jetty/src/main/java
+
+
+#=======================================================================================================================
+# Petstore application settings
+#
+# Demonstrates the Config API + SVL variable resolver: values here are 
referenced from RootResources via
+# $C{Petstore/...} substitutions in @HtmlDocConfig (e.g. the root page header).
+#=======================================================================================================================
+[Petstore]
+
+# Displayed in the root router page header via $C{Petstore/appName}.
+appName = Apache Juneau Petstore
+
+# Chained SVL example: an environment variable read through the Config API, 
with a fallback default.
+buildUser = $E{USER,unknown}
diff --git a/juneau-petstore/juneau-petstore-jetty/pom.xml 
b/juneau-petstore/juneau-petstore-jetty/pom.xml
index 74ddc0c2e8..295d4146c4 100644
--- a/juneau-petstore/juneau-petstore-jetty/pom.xml
+++ b/juneau-petstore/juneau-petstore-jetty/pom.xml
@@ -84,6 +84,13 @@
                        <version>${project.version}</version>
                        <scope>test</scope>
                </dependency>
+               <!-- Next-gen REST client, used by the @Remote typed-client 
(PetStoreClient) round-trip test. -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-rest-client</artifactId>
+                       <version>${project.version}</version>
+                       <scope>test</scope>
+               </dependency>
        </dependencies>
 
        <build>
diff --git 
a/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
 
b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
index 9993ba71de..d6c630aaa8 100644
--- 
a/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
+++ 
b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
@@ -33,6 +33,13 @@ import org.apache.juneau.rest.server.widget.*;
  * {@link ShutdownResource}).  The admin trio is a documented Jetty-only 
non-parity feature — the Spring Boot
  * deployment in {@code juneau-petstore-springboot} does not mount it.
  *
+ * <p>
+ * Also showcases the Config API + SVL variable resolver: the root page's 
header is driven by
+ * {@code $C{Petstore/appName}}, which resolves against the {@code [Petstore]} 
section of
+ * {@code juneau-petstore-jetty.cfg} (the same {@code $C{...}} pattern already 
used by the {@code source} navlink
+ * below, which resolves {@code $C{Source/gitHub}}).  Jetty-only — Spring 
Boot's embedded container has no
+ * {@code .cfg}/{@code Config} equivalent.
+ *
  * <h5 class='section'>See Also:</h5><ul>
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauPetstore";>juneau-petstore</a>
  * </ul>
@@ -59,6 +66,9 @@ import org.apache.juneau.rest.server.widget.*;
        widgets={
                ContentTypeMenuItem.class
        },
+       header={
+               "<h3>$C{Petstore/appName}</h3>"
+       },
        navlinks={
                "api: servlet:/api",
                "stats: servlet:/stats",
diff --git 
a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetStoreClient_Test.java
 
b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetStoreClient_Test.java
new file mode 100644
index 0000000000..d1d0adf257
--- /dev/null
+++ 
b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetStoreClient_Test.java
@@ -0,0 +1,92 @@
+/*
+ * 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.juneau.petstore.jetty;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.parser.*;
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.petstore.client.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.testing.*;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.*;
+
+/**
+ * Integration test that drives the petstore's own REST API through the typed 
{@link PetStoreClient}
+ * {@code @Remote} interface, over a real HTTP round-trip against a live 
Jetty-hosted server.
+ *
+ * <p>
+ * Complements {@link PetstoreJetty_Test} (which exercises the API via a plain 
{@code java.net.http.HttpClient}) by
+ * proving that Juneau's own next-generation {@link RestClient} can consume a 
Juneau REST resource end-to-end via
+ * {@link RestClient#remote(Class)} — no hand-written request/response wiring, 
just the typed interface.
+ */
+@JettyMicroserviceTest
+@TestMethodOrder(MethodOrderer.MethodName.class)
+@SuppressWarnings({
+       "resource" // newClient() returns a Closeable owned by the caller 
(closed via try-with-resources in each test); Eclipse JDT @Owning warning is by 
design.
+})
+class PetStoreClient_Test {
+
+       @RegisterExtension
+       static MicroserviceTestFixture fixture = 
MicroserviceTestFixture.create()
+               .configurations(App.AppConfig.class);
+
+       /**
+        * Builds a JSON-speaking client rooted at the fixture's live server.
+        *
+        * <p>
+        * The next-gen {@link RestClient} has no implicit JSON fallback 
(10.0.0 removed it) — the parser set and
+        * default serializer must be configured explicitly.
+        */
+       private static RestClient newClient() {
+               return RestClient.builder()
+                       .rootUrl(fixture.getRootUrl().toString())
+                       
.parsers(ParserSet.create().add(JsonParser.DEFAULT).build())
+                       .defaultSerializer(JsonSerializer.DEFAULT)
+                       .build();
+       }
+
+       @Test void a01_typedClientListsSeededPets() throws Exception {
+               try (var client = newClient()) {
+                       var svc = client.remote(PetStoreClient.class);
+                       var pets = svc.getPets();
+                       assertEquals(9, pets.size());
+               }
+       }
+
+       @Test void a02_typedClientGetsSeededPetById() throws Exception {
+               try (var client = newClient()) {
+                       var svc = client.remote(PetStoreClient.class);
+                       var pet = svc.getPet(1L);
+                       assertEquals("Mr. Frisky", pet.getName());
+               }
+       }
+
+       @Test void a03_typedClientAddsPet_thenVisibleInList() throws Exception {
+               try (var client = newClient()) {
+                       var svc = client.remote(PetStoreClient.class);
+                       var created = svc.addPet(new 
Pet().setSpecies(Species.DOG).setName("Fido").setPrice(25.0f).setStatus(PetStatus.AVAILABLE));
+                       assertNotEquals(0L, created.getId());
+
+                       var fetched = svc.getPet(created.getId());
+                       assertEquals("Fido", fetched.getName());
+               }
+       }
+}
diff --git 
a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
 
b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
index 99472a6c57..5a7fac9a5a 100644
--- 
a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
+++ 
b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
@@ -137,6 +137,18 @@ class PetstoreJetty_Test extends TestBase {
                assertTrue(body.contains("petstore"), "expected petstore link 
on root: " + body);
        }
 
+       /**
+        * Confirms the Config API + SVL var-resolver showcase: {@code 
RootResources}'s {@code @HtmlDocConfig(header=...)}
+        * references {@code $C{Petstore/appName}}, which resolves against the 
{@code [Petstore]} section of
+        * {@code juneau-petstore-jetty.cfg} — proving the {@code .cfg} value 
reaches the rendered page.
+        */
+       @Test void a02_rootHeaderResolvesConfigSvlAppName() throws Exception {
+               var resp = get("/", "text/html");
+               assertEquals(200, resp.statusCode(), "body: " + resp.body());
+               var body = resp.body();
+               assertTrue(body.contains("Apache Juneau Petstore"), "expected 
$C{Petstore/appName}-resolved header: " + body);
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // b — petstore CRUD over real HTTP, JSON
        
//-----------------------------------------------------------------------------------------------------------------

Reply via email to