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 a295bde584 TODO-239: Port utility-beans/HTML5/image demos into
petstore; drop ATOM/JSON-Schema/SSE.
a295bde584 is described below
commit a295bde5846f05de594395ff553ca5d58f4e512e
Author: James Bognar <[email protected]>
AuthorDate: Wed Jul 15 09:07:49 2026 -0400
TODO-239: Port utility-beans/HTML5/image demos into petstore; drop
ATOM/JSON-Schema/SSE.
3 ported into petstore-core with tests + both deployments wired:
utility-beans
(PetInfoResource), HTML5 bean-builder (PetHtmlResource), and image
upload/serve
(PetPhotoSerializer/PetPhotoParser, now using Pet.photo). 3 consciously
dropped
(ATOM-feed, JSON-Schema, SSE) — no petstore-domain tie-in, coverage
preserved
elsewhere. Closes the TODO-86 acceptance gap left open by TODO-112.
Co-authored-by: Cursor <[email protected]>
---
.../juneau/petstore/marshall/PetPhotoParser.java | 61 ++++++++++++
.../petstore/marshall/PetPhotoSerializer.java | 63 ++++++++++++
.../juneau/petstore/marshall/package-info.java | 26 +++++
.../juneau/petstore/rest/PetHtmlResource.java | 106 +++++++++++++++++++++
.../juneau/petstore/rest/PetInfoResource.java | 93 ++++++++++++++++++
.../juneau/petstore/rest/PetStoreResource.java | 46 +++++++++
.../src/main/resources/petstore/init/Pets.json | 2 +-
.../juneau/petstore/rest/PetHtmlResource_Test.java | 56 +++++++++++
.../juneau/petstore/rest/PetInfoResource_Test.java | 58 +++++++++++
.../petstore/rest/PetStoreResource_Test.java | 42 ++++++++
.../juneau/petstore/jetty/RootResources.java | 2 +
.../juneau/petstore/springboot/RootResources.java | 2 +
12 files changed, 556 insertions(+), 1 deletion(-)
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoParser.java
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoParser.java
new file mode 100644
index 0000000000..c3cc43b178
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoParser.java
@@ -0,0 +1,61 @@
+/*
+ * 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.marshall;
+
+import java.awt.image.*;
+import java.io.*;
+
+import javax.imageio.*;
+
+import org.apache.juneau.marshall.*;
+import org.apache.juneau.marshall.parser.*;
+
+/**
+ * Parses {@code image/png}/{@code image/jpg} byte streams into {@link
BufferedImage} pet photos.
+ *
+ * <p>
+ * Petstore-local port of the deleted {@code juneau-examples-rest} image demo,
relocated here (rather than
+ * {@code juneau-examples-core}) so {@code juneau-petstore-core} stays free of
any dependency on the examples
+ * modules. Wired into {@link
org.apache.juneau.petstore.rest.PetStoreResource#putPetPhoto(long,
BufferedImage)}.
+ *
+ * <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>
+ */
+public class PetPhotoParser extends InputStreamParser {
+
+ /**
+ * Constructor with default settings (consumes image/png and image/jpg).
+ */
+ public PetPhotoParser() {
+ super(create().consumes("image/png,image/jpg"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override /* Parser */
+ @SuppressWarnings({
+ "unchecked" // Type erasure requires cast for image return
+ })
+ public <T> T doParse(ParserSession session, ParserPipe pipe,
ClassMeta<T> type) throws IOException, ParseException {
+ try (var is = pipe.getInputStream()) {
+ var image = ImageIO.read(is);
+ return (T)image;
+ }
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoSerializer.java
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoSerializer.java
new file mode 100644
index 0000000000..f2fc5ab0cf
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/PetPhotoSerializer.java
@@ -0,0 +1,63 @@
+/*
+ * 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.marshall;
+
+import java.awt.image.*;
+import java.io.*;
+
+import javax.imageio.*;
+
+import org.apache.juneau.commons.http.*;
+import org.apache.juneau.marshall.serializer.*;
+
+/**
+ * Serializes {@link BufferedImage} pet photos to {@code image/png}/{@code
image/jpeg} byte streams.
+ *
+ * <p>
+ * Petstore-local port of the deleted {@code juneau-examples-rest} image demo,
relocated here (rather than
+ * {@code juneau-examples-core}) so {@code juneau-petstore-core} stays free of
any dependency on the examples
+ * modules. Wired into {@link
org.apache.juneau.petstore.rest.PetStoreResource#getPetPhoto(long)}.
+ *
+ * <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>
+ */
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for this class hierarchy
+})
+public class PetPhotoSerializer extends OutputStreamSerializer {
+
+ /**
+ * Constructor with default settings (produces image/png and
image/jpeg).
+ */
+ public PetPhotoSerializer() {
+ super(create().produces("image/png,image/jpeg"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void doSerialize(SerializerSession session, SerializerPipe pipe,
Object o) throws IOException, SerializeException {
+ var image = (RenderedImage)o;
+ MediaType mediaType = session.getMediaType();
+ try (var os = pipe.getOutputStream()) {
+ // ImageIO format names are subtypes ("png", "jpeg"),
not MIME types ("image/png").
+ ImageIO.write(image, mediaType.getSubType(), os);
+ }
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/package-info.java
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/package-info.java
new file mode 100644
index 0000000000..e412106f52
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/marshall/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+/**
+ * Petstore-local marshalling support.
+ *
+ * <p>
+ * Custom {@link org.apache.juneau.marshall.serializer.Serializer}/{@link
org.apache.juneau.marshall.parser.Parser}
+ * implementations that are petstore-specific and therefore live here rather
than in a shared marshalling module.
+ * Kept dependency-free of {@code juneau-examples-core} so {@code
juneau-petstore-core} has no example-module
+ * dependency.
+ */
+package org.apache.juneau.petstore.marshall;
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
new file mode 100644
index 0000000000..6a0971af32
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetHtmlResource.java
@@ -0,0 +1,106 @@
+/*
+ * 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.rest;
+
+import static org.apache.juneau.bean.html5.HtmlBuilder.*;
+
+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.*;
+import org.apache.juneau.rest.server.servlet.*;
+
+/**
+ * Petstore-flavored demo of Juneau's HTML5 bean-builder DSL.
+ *
+ * <p>
+ * Ports the deleted {@code juneau-examples-rest} {@code HtmlBeansResource}
demo, swapping its generic
+ * div/form/table samples for hand-built HTML5 fragments rendered from live
petstore data — a "pet card"
+ * {@link Div} and an all-pets {@link Table} — using {@link
org.apache.juneau.bean.html5.HtmlBuilder} static
+ * factory methods instead of relying on the framework's automatic HTML-doc
view.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/HtmlBeans">Using with HTML Beans</a>
+ * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/JuneauPetstore">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/petstore-html",
+ title="Petstore HTML5 bean builder",
+ description="Hand-built HTML5 div/table fragments rendered from live
petstore data."
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetHtmlResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final transient PetStore store = new PetStore();
+
+ /**
+ * Lists the child endpoints.
+ *
+ * @return Descriptive links to the child endpoints.
+ */
+ @RestGet("/")
+ public ResourceDescriptions getChildDescriptions() {
+ return ResourceDescriptions
+ .create()
+ .append("table", "All pets, rendered as a hand-built
HTML5 table")
+ .append("card/1", "A single pet, rendered as a
hand-built HTML5 'pet card' div");
+ }
+
+ /**
+ * Renders a single pet as a hand-built HTML5 "pet card" div.
+ *
+ * @param id The pet ID.
+ * @return A div containing the pet's name, species, price, and status.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestGet("/card/{id}")
+ public Div getPetCard(@Path("id") long id) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ return div(
+ p(b(pet.getName())),
+ p("Species: " + pet.getSpecies()),
+ p("Price: $" + pet.getPrice()),
+ p("Status: " + pet.getStatus())
+ );
+ }
+
+ /**
+ * Renders all pets as a hand-built HTML5 table.
+ *
+ * @return A table with one row per pet (name, species, price, status).
+ */
+ @RestGet("/table")
+ public Table getPetTable() {
+ var rows = new ArrayList<>();
+ rows.add(tr(th("Name"), th("Species"), th("Price"),
th("Status")));
+ for (var pet : store.getPets())
+ rows.add(tr(td(pet.getName()), td(pet.getSpecies()),
td(pet.getPrice()), td(pet.getStatus())));
+ return table(rows.toArray());
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetInfoResource.java
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetInfoResource.java
new file mode 100644
index 0000000000..078a2a5dba
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetInfoResource.java
@@ -0,0 +1,93 @@
+/*
+ * 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.rest;
+
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.beans.*;
+import org.apache.juneau.rest.server.servlet.*;
+
+/**
+ * Petstore-flavored demo of Juneau's REST-server utility beans.
+ *
+ * <p>
+ * Ports the deleted {@code juneau-examples-rest} {@code UtilityBeansResource}
demo, swapping its generic
+ * {@code Address} sample bean for the petstore domain's {@link Pet} bean.
Shows {@link BeanDescription},
+ * {@link Hyperlink}, and {@link SeeOtherRoot} — three small utility beans
intended for use in REST responses
+ * (e.g. {@code OPTIONS} introspection, navigational links, and root-relative
redirects).
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/UtilityBeans">Utility Beans</a>
+ * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/JuneauPetstore">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/petstore-info",
+ title="Petstore utility beans",
+ description="Demonstrates BeanDescription/Hyperlink/SeeOtherRoot
against the Pet domain bean."
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetInfoResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Lists the child endpoints.
+ *
+ * @return Descriptive links to the child endpoints.
+ */
+ @RestGet("/")
+ public ResourceDescriptions getChildDescriptions() {
+ return ResourceDescriptions
+ .create()
+ .append("BeanDescription", "Example of a
BeanDescription bean, describing the Pet domain bean")
+ .append("Hyperlink", "Example of a Hyperlink bean")
+ .append("SeeOtherRoot", "Example of a SeeOtherRoot
bean");
+ }
+
+ /**
+ * Describes the petstore {@link Pet} bean's properties.
+ *
+ * @return A {@link BeanDescription} of {@link Pet}.
+ */
+ @RestGet("/BeanDescription")
+ public BeanDescription getPetBeanDescription() {
+ return BeanDescription.of(Pet.class);
+ }
+
+ /**
+ * Returns a hyperlink back to this resource's root.
+ *
+ * @return A hyperlink pointing at {@code /petstore-info}.
+ */
+ @RestGet("/Hyperlink")
+ public Hyperlink getHyperlink() {
+ return Hyperlink.create("/petstore-info", "Back to
/petstore-info");
+ }
+
+ /**
+ * Redirects to the servlet root.
+ *
+ * @return A redirect to the servlet root.
+ */
+ @RestGet("/SeeOtherRoot")
+ public SeeOtherRoot getSeeOtherRoot() {
+ return SeeOtherRoot.INSTANCE;
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
index 7e19fbfa21..8bcb2b6a34 100644
---
a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
+++
b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
@@ -16,11 +16,14 @@
*/
package org.apache.juneau.petstore.rest;
+import java.awt.image.*;
import java.util.*;
+import java.util.concurrent.*;
import org.apache.juneau.http.*;
import org.apache.juneau.http.response.*;
import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.marshall.*;
import org.apache.juneau.petstore.service.*;
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.servlet.*;
@@ -40,6 +43,8 @@ import org.apache.juneau.rest.server.servlet.*;
* <li>{@code POST /pets} — create pet
* <li>{@code PUT /pets/{id}} — update pet
* <li>{@code DELETE /pets/{id}} — delete pet
+ * <li>{@code GET /pets/{id}/photo} — get pet photo
+ * <li>{@code PUT /pets/{id}/photo} — upload pet photo
* <li>{@code GET /orders} — list orders
* <li>{@code GET /orders/{id}} — get order
* <li>{@code POST /orders} — create order
@@ -71,6 +76,9 @@ public class PetStoreResource extends BasicRestServlet {
/** Backing store. Singleton servlet → singleton store, shared across
requests. */
private final transient PetStore store = new PetStore();
+ /** In-memory photo bytes, keyed by pet ID. Not seeded from JSON —
populated only via {@link #putPetPhoto}. */
+ private final transient Map<Long,BufferedImage> photos = new
ConcurrentHashMap<>();
+
//------------------------------------------------------------------------------------------------------------------
// Pets
//------------------------------------------------------------------------------------------------------------------
@@ -144,6 +152,44 @@ public class PetStoreResource extends BasicRestServlet {
}
}
+ /**
+ * Retrieves the uploaded photo for a pet.
+ *
+ * @param id The pet ID.
+ * @return The photo image.
+ * @throws NotFound If no pet with the given ID exists, or no photo has
been uploaded for it.
+ */
+ @RestGet(path="/pets/{id}/photo", serializers=PetPhotoSerializer.class)
+ public BufferedImage getPetPhoto(@Path("id") long id) {
+ if (store.getPet(id) == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ var image = photos.get(id);
+ if (image == null)
+ throw new NotFound("No photo uploaded for pet: id={0}",
id);
+ return image;
+ }
+
+ /**
+ * Uploads a photo for a pet.
+ *
+ * <p>
+ * On success, also updates the pet's {@link Pet#getPhoto() photo}
field to point back at this endpoint.
+ *
+ * @param id The pet ID.
+ * @param image The photo image.
+ * @return OK.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestPut(path="/pets/{id}/photo", parsers=PetPhotoParser.class)
+ public Ok putPetPhoto(@Path("id") long id, @Content BufferedImage
image) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ photos.put(id, image);
+ pet.setPhoto("/petstore/pets/" + id + "/photo");
+ return Ok.INSTANCE;
+ }
+
//------------------------------------------------------------------------------------------------------------------
// Orders
//------------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
index a78bf19309..4fa3748450 100644
---
a/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
+++
b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
@@ -12,7 +12,7 @@
//
***************************************************************************************************************************
[
- {species:'CAT', name:'Mr. Frisky', price:39.99, tags:['friendly'],
status:'AVAILABLE', photo:'/petstore/photos/cat'},
+ {species:'CAT', name:'Mr. Frisky', price:39.99, tags:['friendly'],
status:'AVAILABLE', photo:'/petstore/pets/1/photo'},
{species:'DOG', name:'Kibbles', price:99.99, tags:['loyal'],
status:'AVAILABLE'},
{species:'RABBIT', name:'Hoppy', price:49.99, tags:['friendly','smells
nice'], status:'AVAILABLE'},
{species:'RABBIT', name:'Hoppy 2', price:49.99, status:'AVAILABLE'},
diff --git
a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetHtmlResource_Test.java
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetHtmlResource_Test.java
new file mode 100644
index 0000000000..adc8af458e
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetHtmlResource_Test.java
@@ -0,0 +1,56 @@
+/*
+ * 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.rest;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+@SuppressWarnings({
+ "resource" // Test helpers return Closeables; Eclipse JDT @Owning
warning is by design.
+})
+class PetHtmlResource_Test extends TestBase {
+
+ private static MockRestClient client() {
+ return MockRestClient.buildJsonLax(PetHtmlResource.class);
+ }
+
+ @Test void a01_getChildDescriptions_listsCardAndTable() throws
Exception {
+ var content =
client().get("/").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains("table"));
+ assertTrue(content.contains("card/1"));
+ }
+
+ @Test void a02_getPetCard_rendersSeededPet() throws Exception {
+ var content =
client().get("/card/1").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains("Mr. Frisky"));
+ assertTrue(content.contains("CAT"));
+ }
+
+ @Test void a03_getPetCard_unknownId_404() throws Exception {
+ client().get("/card/99999").run().assertStatus(404);
+ }
+
+ @Test void a04_getPetTable_rendersAllSeededPets() throws Exception {
+ var content =
client().get("/table").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains("Name"));
+ assertTrue(content.contains("Mr. Frisky"));
+ assertTrue(content.contains("Kibbles"));
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetInfoResource_Test.java
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetInfoResource_Test.java
new file mode 100644
index 0000000000..844dd756a3
--- /dev/null
+++
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetInfoResource_Test.java
@@ -0,0 +1,58 @@
+/*
+ * 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.rest;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+@SuppressWarnings({
+ "resource" // Test helpers return Closeables; Eclipse JDT @Owning
warning is by design.
+})
+class PetInfoResource_Test extends TestBase {
+
+ private static MockRestClient client() {
+ return MockRestClient.buildJsonLax(PetInfoResource.class);
+ }
+
+ @Test void a01_getChildDescriptions_listsAllThree() throws Exception {
+ var content =
client().get("/").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains("BeanDescription"));
+ assertTrue(content.contains("Hyperlink"));
+ assertTrue(content.contains("SeeOtherRoot"));
+ }
+
+ @Test void a02_getPetBeanDescription_describesPet() throws Exception {
+ var content =
client().get("/BeanDescription").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains(Pet.class.getName()));
+ assertTrue(content.contains("species"));
+ assertTrue(content.contains("photo"));
+ }
+
+ @Test void a03_getHyperlink_pointsAtSelf() throws Exception {
+ var content =
client().get("/Hyperlink").run().assertStatus(200).getContent().asString();
+ assertTrue(content.contains("/petstore-info"));
+ }
+
+ @Test void a04_getSeeOtherRoot_redirectsToRoot() throws Exception {
+ var noRedirect =
MockRestClient.create(PetInfoResource.class).disableRedirectHandling().ignoreErrors().build();
+ noRedirect.get("/SeeOtherRoot").run().assertStatus(303);
+ }
+}
diff --git
a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
index 4ed32062c5..47ad04bf0b 100644
---
a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
+++
b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
@@ -19,6 +19,11 @@ package org.apache.juneau.petstore.rest;
import static org.apache.juneau.test.bct.BctAssertions.*;
import static org.junit.jupiter.api.Assertions.*;
+import java.awt.image.*;
+import java.io.*;
+
+import javax.imageio.*;
+
import org.apache.juneau.*;
import org.apache.juneau.petstore.dto.*;
import org.apache.juneau.petstore.dto.Order;
@@ -143,4 +148,41 @@ class PetStoreResource_Test extends TestBase {
c.delete("/users/dvaughn").run().assertStatus(200);
c.get("/users/dvaughn").run().assertStatus(404);
}
+
+
//------------------------------------------------------------------------------------------------------------------
+ // d — pet photos
+
//------------------------------------------------------------------------------------------------------------------
+
+ private static byte[] pngBytes() throws IOException {
+ var image = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
+ try (var baos = new ByteArrayOutputStream()) {
+ ImageIO.write(image, "png", baos);
+ return baos.toByteArray();
+ }
+ }
+
+ @Test void d01_getPetPhoto_notUploaded_404() throws Exception {
+
client().get("/pets/1/photo").accept("image/png").run().assertStatus(404);
+ }
+
+ @Test void d02_getPetPhoto_unknownPet_404() throws Exception {
+
client().get("/pets/99999/photo").accept("image/png").run().assertStatus(404);
+ }
+
+ @Test void d03_putPetPhoto_unknownPet_404() throws Exception {
+ client().put("/pets/99999/photo", new
ByteArrayInputStream(pngBytes())).contentType("image/png")
+ .run().assertStatus(404);
+ }
+
+ @Test void d04_putPetPhoto_thenGet_roundTrip() throws Exception {
+ var c = client();
+ c.put("/pets/1/photo", new
ByteArrayInputStream(pngBytes())).contentType("image/png")
+ .run().assertStatus(200);
+
+ var bytes =
c.get("/pets/1/photo").accept("image/png").run().assertStatus(200).getContent().asBytes();
+ assertTrue(bytes.length > 0);
+
+ var pet =
c.get("/pets/1").run().assertStatus(200).getContent().as(Pet.class);
+ assertEquals("/petstore/pets/1/photo", pet.getPhoto());
+ }
}
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 aaead2cce7..9993ba71de 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
@@ -48,6 +48,8 @@ import org.apache.juneau.rest.server.widget.*;
PetMustacheViewResource.class,
PetFreemarkerViewResource.class,
PetstoreUiResource.class,
+ PetInfoResource.class,
+ PetHtmlResource.class,
ConfigResource.class,
LogsResource.class,
ShutdownResource.class
diff --git
a/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
index dab3c7ca79..fb6a760358 100644
---
a/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
+++
b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
@@ -54,6 +54,8 @@ import org.apache.juneau.rest.server.widget.*;
PetMustacheViewResource.class,
PetFreemarkerViewResource.class,
PetstoreUiResource.class,
+ PetInfoResource.class,
+ PetHtmlResource.class,
HelloResource.class
}
)