You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2019/10/30 20:14:03 UTC

[juneau-petstore] 02/31: Initial contents.

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-petstore.git

commit 54689d2004a6a7cb7ec05b1191032d36241a6400
Author: JamesBognar <ja...@apache.org>
AuthorDate: Mon Sep 9 18:08:40 2019 -0400

    Initial contents.
---
 .gitignore                                         |   6 +
 juneau-petstore-api/.gitignore                     |   6 +
 juneau-petstore-api/src/assembly/bin.xml           |  58 +++
 .../java/org/apache/juneau/petstore/PetStore.java  | 421 ++++++++++++++++
 .../apache/juneau/petstore/dto/CreateOrder.java    |  96 ++++
 .../org/apache/juneau/petstore/dto/CreatePet.java  | 139 ++++++
 .../apache/juneau/petstore/dto/ExpiresAfter.java   |  53 ++
 .../org/apache/juneau/petstore/dto/IdConflict.java |  38 ++
 .../org/apache/juneau/petstore/dto/IdNotFound.java |  38 ++
 .../org/apache/juneau/petstore/dto/InvalidId.java  |  35 ++
 .../apache/juneau/petstore/dto/InvalidLogin.java   |  35 ++
 .../apache/juneau/petstore/dto/InvalidSpecies.java |  35 ++
 .../org/apache/juneau/petstore/dto/InvalidTag.java |  35 ++
 .../juneau/petstore/dto/InvalidUsername.java       |  35 ++
 .../java/org/apache/juneau/petstore/dto/Order.java | 194 ++++++++
 .../apache/juneau/petstore/dto/OrderStatus.java    |  45 ++
 .../java/org/apache/juneau/petstore/dto/Pet.java   | 261 ++++++++++
 .../org/apache/juneau/petstore/dto/PetStatus.java  |  45 ++
 .../org/apache/juneau/petstore/dto/PetTag.java     |  87 ++++
 .../apache/juneau/petstore/dto/PetTagNameSwap.java |  43 ++
 .../org/apache/juneau/petstore/dto/Species.java    |  24 +
 .../org/apache/juneau/petstore/dto/UpdatePet.java  | 122 +++++
 .../java/org/apache/juneau/petstore/dto/User.java  | 213 ++++++++
 .../org/apache/juneau/petstore/dto/UserStatus.java |  44 ++
 .../apache/juneau/petstore/dto/package-info.java   |  18 +
 .../org/apache/juneau/petstore/package-info.java   |  18 +
 juneau-petstore-client/.gitignore                  |   6 +
 juneau-petstore-client/src/assembly/bin.xml        |  58 +++
 .../main/java/org/apache/juneau/petstore/Main.java | 112 +++++
 .../org/apache/juneau/petstore/init/Orders.json    |  18 +
 .../org/apache/juneau/petstore/init/Pets.json      |  24 +
 .../org/apache/juneau/petstore/init/Users.json     |  18 +
 juneau-petstore-server/.gitignore                  |   6 +
 .../juneau-examples-petstore-server.launch         |  15 +
 juneau-petstore-server/src/assembly/bin.xml        |  58 +++
 .../main/java/org/apache/juneau/petstore/App.java  |  34 ++
 .../apache/juneau/petstore/AppConfiguration.java   |  62 +++
 .../juneau/petstore/rest/PetStoreResource.java     | 541 +++++++++++++++++++++
 .../apache/juneau/petstore/rest/RootResources.java |  66 +++
 .../service/AbstractPersistenceService.java        | 273 +++++++++++
 .../juneau/petstore/service/PetStoreService.java   | 329 +++++++++++++
 .../src/main/resources/META-INF/persistence.xml    |  34 ++
 .../src/main/resources/application.properties      |  15 +
 .../src/main/resources/htdocs/background.jpg       | Bin 0 -> 105889 bytes
 .../src/main/resources/htdocs/cat.png              | Bin 0 -> 1878 bytes
 .../src/main/resources/juneau.cfg                  |  70 +++
 .../src/main/resources/log4j.xml                   |  31 ++
 47 files changed, 3914 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..34acf88
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+/target/
+**/.DS_Store
+.classpath
+.project
+/.settings/
+/bin/
diff --git a/juneau-petstore-api/.gitignore b/juneau-petstore-api/.gitignore
new file mode 100644
index 0000000..34acf88
--- /dev/null
+++ b/juneau-petstore-api/.gitignore
@@ -0,0 +1,6 @@
+/target/
+**/.DS_Store
+.classpath
+.project
+/.settings/
+/bin/
diff --git a/juneau-petstore-api/src/assembly/bin.xml b/juneau-petstore-api/src/assembly/bin.xml
new file mode 100644
index 0000000..17e8ca8
--- /dev/null
+++ b/juneau-petstore-api/src/assembly/bin.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ***************************************************************************************************************************
+ * 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.                                              *
+ ***************************************************************************************************************************
+-->
+
+<!--
+	This assembly is used to create the template zip file that developers use to import into Eclipse to start their
+	own projects.
+ -->
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+	<id>bin</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+	<baseDirectory>/</baseDirectory>
+	<includeBaseDirectory>true</includeBaseDirectory>
+	<fileSets>
+		<fileSet>
+			<directory>${basedir}/../juneau-examples-petstore-api</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+				<include>files/**</include>
+				<include>.settings/**</include>
+				<include>.project</include>
+				<include>*.launch</include>
+				<include>*.cfg</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}/build-overlay</directory>
+			<outputDirectory>/</outputDirectory>
+			<filtered>true</filtered>
+		</fileSet>
+	</fileSets>
+	
+</assembly>
\ No newline at end of file
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java
new file mode 100644
index 0000000..8bdfd47
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java
@@ -0,0 +1,421 @@
+// ***************************************************************************************************************************
+// * 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;
+
+import static org.apache.juneau.http.HttpMethodName.*;
+
+import java.util.*;
+
+import org.apache.juneau.jsonschema.annotation.Items;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.remote.*;
+import org.apache.juneau.http.exception.*;
+import org.apache.juneau.http.response.*;
+
+/**
+ * Defines the interface for both the server-side and client-side pet store application.
+ *
+ * <p>
+ * On the server side, this interface is implemented by the <c>PetStoreResource</c> class.
+ *
+ * <p>
+ * On the client side, this interface is instantiated as a proxy using the <c>RestClient.getRemoteProxy()</c> method.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@RemoteResource(path="/petstore")
+public interface PetStore {
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Pets
+	//------------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns all pets in the database.
+	 *
+	 * @return All pets in the database.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/pet")
+	public Collection<Pet> getPets() throws NotAcceptable;
+
+	/**
+	 * Returns a pet from the database.
+	 *
+	 * @param petId The ID of the pet to retrieve.
+	 * @return The pet.
+	 * @throws IdNotFound Pet was not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(path="/pet/{petId}") /* method inferred from method name */
+	public Pet getPet(
+		@Path(
+			name="petId",
+			description="ID of pet to return",
+			example="123"
+		)
+		long petId
+	) throws IdNotFound, NotAcceptable;
+
+	/**
+	 * Adds a pet to the database.
+	 *
+	 * @param pet The pet data to add to the database.
+	 * @return {@link Ok} if successful.
+	 * @throws IdConflict ID already in use.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=POST, path="/pet")
+	public long createPet(
+		@Body(
+			description="Pet object to add to the store"
+		) CreatePet pet
+	) throws IdConflict, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Updates a pet in the database.
+	 *
+	 * @param pet The pet data to add to the database.
+	 * @return {@link Ok} if successful.
+	 * @throws IdNotFound ID not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=PUT, path="/pet/{petId}")
+	public Ok updatePet(
+		@Body(
+			description="Pet object that needs to be added to the store"
+		) UpdatePet pet
+	) throws IdNotFound, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Find all pets with the matching statuses.
+	 *
+	 * @param status The statuses to match against.
+	 * @return The pets that match the specified statuses.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/pet/findByStatus")
+	public Collection<Pet> findPetsByStatus(
+		@Query(
+			name="status",
+			description="Status values that need to be considered for filter.",
+			required=true,
+			type="array",
+			collectionFormat="csv",
+			items=@Items(
+				type="string",
+				_enum="AVAILABLE,PENDING,SOLD",
+				_default="AVAILABLE"
+			),
+			example="AVALIABLE,PENDING"
+		)
+		PetStatus[] status
+	) throws NotAcceptable;
+
+	/**
+	 * Find all pets with the specified tags.
+	 *
+	 * @param tags The tags to match against.
+	 * @return The pets that match the specified tags.
+	 * @throws InvalidTag Invalid tag was specified.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/pet/findByTags")
+	@Deprecated
+	public Collection<Pet> findPetsByTags(
+		@Query(
+			name="tags",
+			description="Tags to filter by",
+			required=true,
+			example="['tag1','tag2']"
+		)
+		String[] tags
+	) throws InvalidTag, NotAcceptable;
+
+	/**
+	 * Deletes the specified pet.
+	 *
+	 * @param apiKey Security key.
+	 * @param petId ID of pet to delete.
+	 * @return {@link Ok} if successful.
+	 * @throws IdNotFound Pet not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=DELETE, path="/pet/{petId}")
+	public Ok deletePet(
+		@Header(
+			name="api_key",
+			description="Security API key",
+			required=true,
+			example="foobar"
+		)
+		String apiKey,
+		@Path(
+			name="petId",
+			description="Pet id to delete",
+			example="123"
+		)
+		long petId
+	) throws IdNotFound, NotAcceptable;
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Orders
+	//------------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns all orders in the database.
+	 *
+	 * @return All orders in the database.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/store/order")
+	public Collection<Order> getOrders() throws NotAcceptable;
+
+	/**
+	 * Returns an order from the database.
+	 *
+	 * @param orderId The ID of the order to retreieve.
+	 * @return The retrieved order.
+	 * @throws InvalidId ID was invalid.
+	 * @throws IdNotFound Order was not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/store/order/{orderId}")
+	public Order getOrder(
+		@Path(
+			name="orderId",
+			description="ID of order to fetch",
+			maximum="1000",
+			minimum="1",
+			example="123"
+		)
+		long orderId
+	) throws InvalidId, IdNotFound, NotAcceptable;
+
+	/**
+	 * Adds an order to the database.
+	 *
+	 * @param petId Id of pet to order.
+	 * @param username The username of the user placing the order.
+	 * @return The ID of the order.
+	 * @throws IdConflict ID was already in use.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=POST, path="/store/order")
+	public long placeOrder(
+		@FormData(
+			name="petId",
+			description="Pet ID"
+		)
+		long petId,
+		@FormData(
+			name="username",
+			description="The username of the user creating the order"
+		)
+		String username
+	) throws IdConflict, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Deletes an order from the database.
+	 *
+	 * @param orderId The order ID.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidId ID not valid.
+	 * @throws IdNotFound Order not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=DELETE, path="/store/order/{orderId}")
+	public Ok deleteOrder(
+		@Path(
+			name="orderId",
+			description="ID of the order that needs to be deleted",
+			minimum="1",
+			example="5"
+		)
+		long orderId
+	) throws InvalidId, IdNotFound, NotAcceptable;
+
+	/**
+	 * Returns an inventory of pet statuses and counts.
+	 *
+	 * @return An inventory of pet statuses and counts.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/store/inventory")
+	public Map<PetStatus,Integer> getStoreInventory() throws NotAcceptable;
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Users
+	//------------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns all users in the database.
+	 *
+	 * @return All users in the database.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/user")
+	public Collection<User> getUsers() throws NotAcceptable;
+
+	/**
+	 * Returns a user from the database.
+	 *
+	 * @param username The username.
+	 * @return The user.
+	 * @throws InvalidUsername Invalid username.
+	 * @throws IdNotFound username not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/user/{username}")
+	public User getUser(
+		@Path(
+			name="username",
+			description="The name that needs to be fetched. Use user1 for testing."
+		)
+		String username
+	) throws InvalidUsername, IdNotFound, NotAcceptable;
+
+	/**
+	 * Adds a new user to the database.
+	 *
+	 * @param user The user to add to the database.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidUsername Username was invalid.
+	 * @throws IdConflict Username already in use.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=POST, path="/user")
+	public Ok createUser(
+		@Body(
+			description="Created user object"
+		)
+		User user
+	) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Bulk creates users.
+	 *
+	 * @param users The users to add to the database.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidUsername Username was invalid.
+	 * @throws IdConflict Username already in use.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=POST, path="/user/createWithArray")
+	public Ok createUsers(
+		@Body(
+			description="List of user objects"
+		)
+		User[] users
+	) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Updates a user in the database.
+	 *
+	 * @param username The username.
+	 * @param user The updated information.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidUsername Username was invalid.
+	 * @throws IdNotFound User was not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 * @throws UnsupportedMediaType Unsupported <c>Content-Type</c> header specified.
+	 */
+	@RemoteMethod(method=PUT, path="/user/{username}")
+	public Ok updateUser(
+		@Path(
+			name="username",
+			description="Name that need to be updated"
+		)
+		String username,
+		@Body(
+			description="Updated user object"
+		)
+		User user
+	) throws InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType;
+
+	/**
+	 * Deletes a user from the database.
+	 *
+	 * @param username The username.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidUsername Username was not valid.
+	 * @throws IdNotFound User was not found.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=DELETE, path="/user/{username}")
+	public Ok deleteUser(
+		@Path(
+			name="username",
+			description="The name that needs to be deleted"
+		)
+		String username
+	) throws InvalidUsername, IdNotFound, NotAcceptable;
+
+	/**
+	 * User login.
+	 *
+	 * @param username The username for login.
+	 * @param password The password for login in clear text.
+	 * @param rateLimit Calls per hour allowed by the user.
+	 * @param expiresAfter The <bc>Expires-After</bc> response header.
+	 * @param req The servlet request.
+	 * @param res The servlet response.
+	 * @return {@link Ok} if successful.
+	 * @throws InvalidLogin Login was unsuccessful.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/user/login")
+	public Ok login(
+		@Query(
+			name="username",
+			description="The username for login.",
+			required=true,
+			example="myuser"
+		)
+		String username,
+		@Query(
+			name="password",
+			description="The password for login in clear text.",
+			required=true,
+			example="abc123"
+		)
+		String password,
+		@ResponseHeader(
+			name="X-Rate-Limit",
+			type="integer",
+			format="int32",
+			description="Calls per hour allowed by the user.",
+			example="123"
+		)
+		Value<Integer> rateLimit,
+		Value<ExpiresAfter> expiresAfter
+	) throws InvalidLogin, NotAcceptable;
+
+	/**
+	 * User logout.
+	 *
+	 * @return {@link Ok} if successful.
+	 * @throws NotAcceptable Unsupported <c>Accept</c> header specified.
+	 */
+	@RemoteMethod(method=GET, path="/user/logout")
+	public Ok logout() throws NotAcceptable;
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java
new file mode 100644
index 0000000..db9686e
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java
@@ -0,0 +1,96 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.annotation.*;
+
+/**
+ * Bean for creating {@link Order} objects.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(fluentSetters=true, properties="petId,username")
+public class CreateOrder {
+
+	private long petId;
+	private String username;
+
+	/**
+	 * Optional constructor.
+	 *
+	 * @param petId The <bc>petId</bc> property value.
+	 * @param username The <bc>username</bc> property value.
+	 */
+	@BeanConstructor(properties="petId,username")
+	public CreateOrder(long petId, String username) {
+		this.petId = petId;
+		this.username = username;
+	}
+
+	/**
+	 * Constructor needed by JPA.
+	 */
+	public CreateOrder() {}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>petId</bc> property value.
+	 */
+	public long getPetId() {
+		return petId;
+	}
+
+	/**
+	 * @param value The <bc>petId</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreateOrder petId(long value) {
+		this.petId = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>username</bc> property value.
+	 */
+	public String getUsername() {
+		return username;
+	}
+
+	/**
+	 * @param value The <bc>username</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreateOrder username(String value) {
+		this.username = value;
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Used to populate Swagger examples.
+	 * Example is inferred from the method name.
+	 *
+	 * @return An example POJO.
+	 */
+	public static CreateOrder example() {
+		return new CreateOrder(123, "sampleuser");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java
new file mode 100644
index 0000000..2064cc2
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java
@@ -0,0 +1,139 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+
+/**
+ * Bean for creating {@link Pet} objects.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(fluentSetters=true, properties="name,price,species,tags")
+public class CreatePet {
+
+	@Schema(description="Pet name.", minLength=3, maxLength=50)
+	private String name;
+
+	@Schema(description="Price of pet.", maximum="999.99")
+	private float price;
+
+	@Schema(description="Pet species.")
+	private Species species;
+
+	@Schema(description="Pet attributes.", example="friendly,smart")
+	private String[] tags;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param name The <bc>name</bc> property value.
+	 * @param price The <bc>price</bc> property value.
+	 * @param species The <bc>species</bc> property value.
+	 * @param tags The <bc>tags</bc> property value.
+	 * @param photo The <bc>photo</bc> property value.
+	 */
+	public CreatePet(String name, float price, Species species, String[] tags) {
+		this.name = name;
+		this.price = price;
+		this.species = species;
+		this.tags = tags;
+	}
+
+	/**
+	 * Empty constructor.
+	 */
+	public CreatePet() {}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>name</bc> property value.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param value The <bc>name</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreatePet name(String value) {
+		this.name = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>price</bc> property value.
+	 */
+	public float getPrice() {
+		return price;
+	}
+
+	/**
+	 * @param value The <bc>price</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreatePet price(float value) {
+		this.price = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>species</bc> property value.
+	 */
+	public Species getSpecies() {
+		return species;
+	}
+
+	/**
+	 * @param value The <bc>species</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreatePet species(Species value) {
+		this.species = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>tags</bc> property value.
+	 */
+	public String[] getTags() {
+		return tags;
+	}
+
+	/**
+	 * @param value The <bc>tags</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public CreatePet tags(String...value) {
+		this.tags = value;
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return An example POJO.
+	 */
+	public static CreatePet example() {
+		return new CreatePet("Doggie", 9.99f, Species.DOG, new String[]{"smart","friendly"});
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java
new file mode 100644
index 0000000..8273edf
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java
@@ -0,0 +1,53 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import java.util.*;
+
+import org.apache.juneau.http.annotation.*;
+
+/**
+ * X-Expires-After custom HTTP header.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@ResponseHeader(
+	name="X-Expires-After",
+	type="string",
+	format="date-time",
+	description="Date in UTC when token expires",
+	example="2012-10-21"
+)
+public class ExpiresAfter {
+	private final Calendar c;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param d The header value.
+	 */
+	public ExpiresAfter(Date d) {
+		this.c = new GregorianCalendar();
+		c.setTime(d);
+	}
+
+	/**
+	 * The header value.
+	 * @return The header value.
+	 */
+	public Calendar toCalendar() {
+		return c;
+	}
+}
\ No newline at end of file
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java
new file mode 100644
index 0000000..5a22a1d
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java
@@ -0,0 +1,38 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when trying to add an entry where the ID is already in use.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="ID already in use")
+public class IdConflict extends Conflict {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param id The duplicate ID.
+	 * @param c The object type..
+	 */
+	public IdConflict(Object id, Class<?> c) {
+		super("ID ''{0}'' already in use for type ''{1}''", id, c.getSimpleName());
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java
new file mode 100644
index 0000000..b086f8e
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java
@@ -0,0 +1,38 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when trying to add an entry where the ID is already in use.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="ID not found")
+public class IdNotFound extends NotFound {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param id The duplicate ID.
+	 * @param c The object type..
+	 */
+	public IdNotFound(Object id, Class<?> c) {
+		super("ID ''{0}'' not found for type ''{1}''", id, c.getSimpleName());
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java
new file mode 100644
index 0000000..d7ee807
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when trying to add an entry where the ID is already in use.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="Invalid ID provided")
+public class InvalidId extends BadRequest {
+
+	/**
+	 * Constructor.
+	 */
+	public InvalidId() {
+		super("Invalid ID provided.");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java
new file mode 100644
index 0000000..25f6bd9
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when an invalid username or password is provided.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="Invalid username or password provided")
+public class InvalidLogin extends Unauthorized {
+
+	/**
+	 * Constructor.
+	 */
+	public InvalidLogin() {
+		super("Invalid username or password.");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java
new file mode 100644
index 0000000..19cef69
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when an invalid species is looked up.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="Invalid species provided")
+public class InvalidSpecies extends BadRequest {
+
+	/**
+	 * Constructor.
+	 */
+	public InvalidSpecies() {
+		super("Invalid species provided.");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java
new file mode 100644
index 0000000..4e2199e
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when trying to add an entry where the ID is already in use.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="Invalid tag provided")
+public class InvalidTag extends BadRequest {
+
+	/**
+	 * Constructor.
+	 */
+	public InvalidTag() {
+		super("Invalid tag provided.  Must be at most 8 characters or digits.");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java
new file mode 100644
index 0000000..46644a3
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.exception.*;
+
+/**
+ * Exception thrown when trying to add an entry where the ID is already in use.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@SuppressWarnings("serial")
+@Response(description="Invalid username provided")
+public class InvalidUsername extends BadRequest {
+
+	/**
+	 * Constructor.
+	 */
+	public InvalidUsername() {
+		super("Invalid username provided.  Must be between 3 and 8 characters or digits.");
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java
new file mode 100644
index 0000000..27fb0b3
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java
@@ -0,0 +1,194 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import static javax.persistence.TemporalType.*;
+
+import java.util.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.transforms.*;
+
+/**
+ * Order bean.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(fluentSetters=true, properties="id,petId,username,status,shipDate")
+@Example("{id:123,petId:456,shipDate:'2012-12-21',status:'APPROVED'}")
+@Entity(name="PetstoreOrder")
+public class Order {
+
+	@Column @Id @GeneratedValue
+	@Schema(description="Unique identifier for this order.")
+	@Html(link="servlet:/store/order/{id}")
+	private long id;
+
+	@Column
+	@Schema(description="Pet unique identifier.")
+	@Html(link="servlet:/pet/{id}")
+	private long petId;
+
+	@Column(length=20)
+	@Schema(description="User who created this order.", minLength=3, maxLength=20)
+	@Html(link="servlet:/user/{username}")
+	private String username;
+
+	@Column
+	@Enumerated(EnumType.STRING)
+	@Schema(description="The current order status.")
+	private OrderStatus status;
+
+	@Column @Temporal(TIMESTAMP)
+	@Schema(description="The ship date for this order.", format="date-time")
+	@Swap(TemporalDateSwap.IsoLocalDate.class)
+	private Date shipDate;
+
+	/**
+	 * Applies the specified create data to this order.
+	 *
+	 * @param o The create data to apply.
+	 * @return This object.
+	 */
+	public Order apply(CreateOrder o) {
+		this.petId = o.getPetId();
+		this.username = o.getUsername();
+		return this;
+	}
+
+	/**
+	 * Applies the specified order this order.
+	 *
+	 * @param o The order to apply.
+	 * @return This object.
+	 */
+	public Order apply(Order o) {
+		this.id = o.getId();
+		this.petId = o.getPetId();
+		this.username = o.getUsername();
+		this.status = o.getStatus();
+		this.shipDate = o.getShipDate();
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>id</bc> property value.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param value The <bc>id</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Order id(long value) {
+		this.id = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>shipDate</bc> property value.
+	 */
+	public Date getShipDate() {
+		return shipDate;
+	}
+
+	/**
+	 * @param value The <bc>shipDate</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Order shipDate(Date value) {
+		this.shipDate = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>status</bc> property value.
+	 */
+	public OrderStatus getStatus() {
+		return status;
+	}
+
+	/**
+	 * @param value The <bc>status</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Order status(OrderStatus value) {
+		this.status = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>petId</bc> property value.
+	 */
+	public long getPetId() {
+		return petId;
+	}
+
+	/**
+	 * @param value The <bc>petId</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Order petId(long value) {
+		this.petId = value;;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>username</bc> property value.
+	 */
+	public String getUsername() {
+		return username;
+	}
+
+	/**
+	 * @param value The <bc>username</bc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Order username(String value) {
+		this.username = value;
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * This shows an example generated from a static method.
+	 *
+	 * @return The example POJO.
+	 */
+	@Example
+	public static Order example() {
+		return new Order()
+			.id(123)
+			.username("sampleuser")
+			.petId(456)
+			.status(OrderStatus.APPROVED)
+			.shipDate(DateUtils.parseISO8601("2020-10-10"))
+		;
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java
new file mode 100644
index 0000000..0c5e01e
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Enum of all possible order statuses.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Html(render=OrderStatus.OrderStatusRender.class)
+@SuppressWarnings("javadoc")
+public enum OrderStatus {
+	PLACED, APPROVED, DELIVERED;
+
+	/**
+	 * Used to control how this enum is rendered in HTML view.
+	 */
+	public static class OrderStatusRender extends HtmlRender<OrderStatus> {
+		@Override /* HtmlRender */
+		public String getStyle(SerializerSession session, OrderStatus value) {
+			switch(value) {
+				case PLACED:  return "background-color:#5cb85c;text-align:center;vertical-align:middle;";
+				case APPROVED:  return "background-color:#f0ad4e;text-align:center;vertical-align:middle;";
+				case DELIVERED:  return "background-color:#777;text-align:center;vertical-align:middle;";
+				default:  return "background-color:#888;text-align:center;vertical-align:middle;";
+			}
+		}
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java
new file mode 100644
index 0000000..cb9dff0
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java
@@ -0,0 +1,261 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import static javax.persistence.EnumType.*;
+
+import java.util.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.html.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Pet bean.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(typeName="Pet", fluentSetters=true, properties="id,species,name,tags,price,status")
+@Entity(name="PetstorePet")
+public class Pet {
+
+	@Column @Id @GeneratedValue
+	@Schema(description="Unique identifier for this pet.")
+	@Html(link="servlet:/pet/{id}")
+	private long id;
+
+	@Column(length=50)
+	@Schema(description="Pet name.", minLength=3, maxLength=50)
+	private String name;
+
+	@Column
+	@Schema(description="Price of pet.", maximum="999.99")
+	@Html(render=PriceRender.class)
+	private float price;
+
+	@Column
+	@Schema(description="Pet species.")
+	private Species species;
+
+	@ElementCollection @OrderColumn
+	@Schema(description="Pet attributes.", example="friendly,smart")
+	private List<String> tags;
+
+	@Column @Enumerated(STRING)
+	@Schema(description="Pet species.")
+	private PetStatus status;
+
+	/**
+	 * Applies the specified data to this object.
+	 *
+	 * @param x The data to apply.
+	 * @return This object.
+	 */
+	public Pet apply(CreatePet x) {
+		this.name = x.getName();
+		this.price = x.getPrice();
+		this.species = x.getSpecies();
+		this.tags = x.getTags() == null ? null : Arrays.asList(x.getTags());
+		return this;
+	}
+
+	/**
+	 * Applies the specified data to this object.
+	 *
+	 * @param x The data to apply.
+	 * @return This object.
+	 */
+	public Pet apply(UpdatePet x) {
+		this.id = x.getId();
+		this.name = x.getName();
+		this.price = x.getPrice();
+		this.species = x.getSpecies();
+		this.tags = Arrays.asList(x.getTags());
+		this.status = x.getStatus();
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>id</jc> property value.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param value The <bc>id</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet id(long value) {
+		this.id = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>name</jc> property value.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param value The <bc>name</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet name(String value) {
+		this.name = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>price</jc> property value.
+	 */
+	public float getPrice() {
+		return price;
+	}
+
+	/**
+	 * @param value The <bc>price</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet price(float value) {
+		this.price = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>species</jc> property value.
+	 */
+	public Species getSpecies() {
+		return species;
+	}
+
+	/**
+	 * @param value The <bc>species</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet species(Species value) {
+		this.species = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>tags</jc> property value.
+	 */
+	public List<String> getTags() {
+		return tags;
+	}
+
+	/**
+	 * @param value The <bc>tags</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet tags(List<String> value) {
+		this.tags = value;
+		return this;
+	}
+
+	/**
+	 * @param value The <bc>tags</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet tags(String...value) {
+		this.tags = Arrays.asList(value);
+		return this;
+	}
+
+	/**
+	 * @return The <bc>status</jc> property value.
+	 */
+	public PetStatus getStatus() {
+		return status;
+	}
+
+	/**
+	 * @param value The <bc>status</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public Pet status(PetStatus value) {
+		this.status = value;
+		return this;
+	}
+
+	/**
+	 * @param statuses The statuses to match against.
+	 * @return <jk>true</jk> if this pet matches at least one of the specified statuses.
+	 */
+	public boolean hasStatus(PetStatus...statuses) {
+		for (PetStatus status : statuses)
+			if (this.status == status)
+				return true;
+		return false;
+	}
+
+	/**
+	 * @param tags The tags to match against.
+	 * @return <jk>true</jk> if this pet matches at least one of the specified tags.
+	 */
+	public boolean hasTag(String...tags) {
+		for (String tag : tags)
+			for (String t : this.tags)
+				if (t.equals(tag))
+					return true;
+		return false;
+	}
+
+	/**
+	 * @return Edit page link.
+	 */
+	public java.net.URI getEdit() {
+		return java.net.URI.create("servlet:/pet/edit/{id}");
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * This shows an example generated from a static method.
+	 *
+	 * @return POJO example.
+	 */
+	@Example
+	public static Pet example() {
+		return new Pet()
+			.id(123)
+			.species(Species.DOG)
+			.name("Doggie")
+			.tags("friendly","smart")
+			.status(PetStatus.AVAILABLE);
+	}
+
+	/**
+	 * Used to control format of prices in HTML view.
+	 */
+	public static final class PriceRender extends HtmlRender<Float> {
+		@Override
+		public Object getContent(SerializerSession session, Float value) {
+			return value == null ? null : String.format("$%.2f", value);
+		}
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java
new file mode 100644
index 0000000..42abc3a
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Enum of all possible pet statuses.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Html(render=PetStatus.PetStatusRender.class)
+@SuppressWarnings("javadoc")
+public enum PetStatus {
+	AVAILABLE, PENDING, SOLD, UNKNOWN;
+
+	/**
+	 * Used to control how this enum is rendered in HTML view.
+	 */
+	public static class PetStatusRender extends HtmlRender<PetStatus> {
+		@Override /* HtmlRender */
+		public String getStyle(SerializerSession session, PetStatus value) {
+			switch(value) {
+				case AVAILABLE:  return "background-color:#5cb85c;text-align:center;vertical-align:middle;";
+				case PENDING:  return "background-color:#f0ad4e;text-align:center;vertical-align:middle;";
+				case SOLD:  return "background-color:#888;text-align:center;vertical-align:middle;";
+				default:  return "background-color:#777;text-align:center;vertical-align:middle;";
+			}
+		}
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java
new file mode 100644
index 0000000..34577ab
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java
@@ -0,0 +1,87 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Pet tag bean.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(typeName="Tag", fluentSetters=true)
+@Swap(PetTagNameSwap.class)
+public class PetTag {
+	private long id;
+	private String name;
+
+	/**
+	 * @return The <bc>id</jc> property value.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param value The <bc>id</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public PetTag id(long value) {
+		this.id = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>name</jc> property value.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param value The <bc>name</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public PetTag name(String value) {
+		this.name = value;
+		return this;
+	}
+
+	/**
+	 * @return POJO example.
+	 */
+	@Example
+	public static PetTag example() {
+		return new PetTag()
+			.id(123)
+			.name("MyTag");
+	}
+
+	/**
+	 * @param tags Tags to convert to a simple string.
+	 * @return The specified tags as a simple comma-delimited list.
+	 */
+	public static String asString(List<PetTag> tags) {
+		if (tags == null)
+			return "";
+		List<String> l = new ArrayList<>(tags.size());
+		for (PetTag t : tags)
+			l.add(t.getName());
+		return StringUtils.join(l, ',');
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java
new file mode 100644
index 0000000..7e1442f
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java
@@ -0,0 +1,43 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.transform.*;
+
+/**
+ * Swap for {@link PetTag} beans.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+public class PetTagNameSwap extends PojoSwap<PetTag,String> {
+
+	/**
+	 * Swap PetTag with name.
+	 */
+	@Override
+	public String swap(BeanSession bs, PetTag o) throws Exception {
+		return o.getName();
+	}
+
+	/**
+	 * This is only applicable to HTML serialization.
+	 */
+	@Override
+	public MediaType[] forMediaTypes() {
+		return new MediaType[] { MediaType.HTML };
+	}
+}
\ No newline at end of file
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java
new file mode 100644
index 0000000..90a54e3
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java
@@ -0,0 +1,24 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+/**
+ * Enum of all possible animal types.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+public enum Species {
+	BIRD, CAT, DOG, FISH, MOUSE, RABBIT, SNAKE;
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java
new file mode 100644
index 0000000..d4b671f
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java
@@ -0,0 +1,122 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+
+/**
+ * Bean for updating {@link Pet} objects.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(fluentSetters=true, properties="id,name,price,species,tags,status")
+public class UpdatePet extends CreatePet {
+
+	@Schema(description="Pet identifier.", minimum="1")
+	private long id;
+
+	@Schema(description="Updated pet status.")
+	private PetStatus status;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param id The <bc>id</bc> property value.
+	 * @param name The <bc>name</bc> property value.
+	 * @param price The <bc>price</bc> property value.
+	 * @param species The <bc>species</bc> property value.
+	 * @param tags The <bc>tags</bc> property value.
+	 * @param status The <bc>status</bc> property value.
+	 */
+	public UpdatePet(long id, String name, float price, Species species, String[] tags, PetStatus status) {
+		super(name, price, species, tags);
+		this.id = id;
+		this.status = status;
+	}
+
+	/**
+	 * Empty constructor.
+	 */
+	public UpdatePet() {}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>id</jc> property value.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param value The <bc>id</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public UpdatePet id(long value) {
+		this.id = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>status</jc> property value.
+	 */
+	public PetStatus getStatus() {
+		return status;
+	}
+
+	/**
+	 * @param value The <bc>status</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public UpdatePet status(PetStatus value) {
+		this.status = value;
+		return this;
+	}
+
+	@Override
+	public UpdatePet name(String value) {
+		super.name(value);
+		return this;
+	}
+
+	@Override
+	public UpdatePet price(float value) {
+		super.price(value);
+		return this;
+	}
+
+	@Override
+	public UpdatePet species(Species value) {
+		super.species(value);
+		return this;
+	}
+
+	@Override
+	public UpdatePet tags(String...value) {
+		super.tags(value);
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static UpdatePet example() {
+		return new UpdatePet(123, "Doggie", 9.99f, Species.DOG, new String[]{"smart","friendly"}, PetStatus.SOLD);
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java
new file mode 100644
index 0000000..eefa4c5
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java
@@ -0,0 +1,213 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import static javax.persistence.EnumType.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+
+/**
+ * User bean.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Bean(typeName="User", fluentSetters=true, properties="username,firstName,lastName,email,password,phone,userStatus")
+@Entity(name="PetstoreUser")
+public class User {
+
+	@Id
+	@Column(length=8)
+	@Schema(description="Username.", minLength=3, maxLength=8)
+	@Html(link="servlet:/user/{username}")
+	private String username;
+
+	@Column(length=50)
+	@Schema(description="First name.", maxLength=50)
+	private String firstName;
+
+	@Column(length=50)
+	@Schema(description="First name.", maxLength=50)
+	private String lastName;
+
+	@Column(length=50)
+	@Schema(description="First name.", maxLength=50, pattern="\\S+\\@\\S+")
+	private String email;
+
+	@Column(length=8)
+	@Schema(description="Password.", minLength=3, maxLength=8, pattern="[\\w\\d]{3,8}")
+	private String password;
+
+	@Column
+	@Schema(description="Phone number.", minLength=12, maxLength=12, pattern="\\d{3}\\-\\d{3}\\-\\d{4}")
+	private String phone;
+
+	@Column
+	@Enumerated(STRING)
+	private UserStatus userStatus;
+
+	/**
+	 * Applies the specified data to this object.
+	 *
+	 * @param c The data to apply.
+	 * @return This object.
+	 */
+	public User apply(User c) {
+		this.username = c.getUsername();
+		this.firstName = c.getFirstName();
+		this.lastName = c.getLastName();
+		this.email = c.getEmail();
+		this.password = c.getPassword();
+		this.phone = c.getPhone();
+		this.userStatus = c.getUserStatus();
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * @return The <bc>username</jc> property value.
+	 */
+	public String getUsername() {
+		return username;
+	}
+
+	/**
+	 * @param value The <bc>username</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User username(String value) {
+		this.username = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>firstName</jc> property value.
+	 */
+	public String getFirstName() {
+		return firstName;
+	}
+
+	/**
+	 * @param value The <bc>firstName</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User firstName(String value) {
+		this.firstName = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>lastName</jc> property value.
+	 */
+	public String getLastName() {
+		return lastName;
+	}
+
+	/**
+	 * @param value The <bc>lastName</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User lastName(String value) {
+		this.lastName = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>email</jc> property value.
+	 */
+	public String getEmail() {
+		return email;
+	}
+
+	/**
+	 * @param value The <bc>email</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User email(String value) {
+		this.email = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>password</jc> property value.
+	 */
+	public String getPassword() {
+		return password;
+	}
+
+	/**
+	 * @param value The <bc>password</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User password(String value) {
+		this.password = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>phone</jc> property value.
+	 */
+	public String getPhone() {
+		return phone;
+	}
+
+	/**
+	 * @param value The <bc>phone</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User phone(String value) {
+		this.phone = value;
+		return this;
+	}
+
+	/**
+	 * @return The <bc>userStatus</jc> property value.
+	 */
+	public UserStatus getUserStatus() {
+		return userStatus;
+	}
+
+	/**
+	 * @param value The <bc>userStatus</jc> property value.
+	 * @return This object (for method chaining).
+	 */
+	public User userStatus(UserStatus value) {
+		this.userStatus = value;
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * This shows an example generated from a static method.
+	 */
+	@Example
+	public static User EXAMPLE = new User()
+		.username("billy")
+		.firstName("Billy")
+		.lastName("Bob")
+		.email("billy@apache.org")
+		.userStatus(UserStatus.ACTIVE)
+		.phone("111-222-3333");
+
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java
new file mode 100644
index 0000000..1049c45
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java
@@ -0,0 +1,44 @@
+// ***************************************************************************************************************************
+// * 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.dto;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Enum of all possible user statuses.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@Html(render=UserStatus.UserStatusRender.class)
+@SuppressWarnings("javadoc")
+public enum UserStatus {
+	ACTIVE, INACTIVE;
+
+	/**
+	 * Used to control how this enum is rendered in HTML view.
+	 */
+	public static class UserStatusRender extends HtmlRender<UserStatus> {
+		@Override /* HtmlRender */
+		public String getStyle(SerializerSession session, UserStatus value) {
+			switch(value) {
+				case ACTIVE:  return "background-color:#5cb85c;text-align:center;vertical-align:middle;";
+				case INACTIVE:  return "background-color:#888;text-align:center;vertical-align:middle;";
+				default:  return "";
+			}
+		}
+	}
+}
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java
new file mode 100755
index 0000000..3b1ff90
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java
@@ -0,0 +1,18 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ***************************************************************************************************************************
+
+/**
+ * Examples
+ */
+package org.apache.juneau.petstore.dto;
+
diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java
new file mode 100755
index 0000000..7f2bf15
--- /dev/null
+++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java
@@ -0,0 +1,18 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ***************************************************************************************************************************
+
+/**
+ * Examples
+ */
+package org.apache.juneau.petstore;
+
diff --git a/juneau-petstore-client/.gitignore b/juneau-petstore-client/.gitignore
new file mode 100644
index 0000000..34acf88
--- /dev/null
+++ b/juneau-petstore-client/.gitignore
@@ -0,0 +1,6 @@
+/target/
+**/.DS_Store
+.classpath
+.project
+/.settings/
+/bin/
diff --git a/juneau-petstore-client/src/assembly/bin.xml b/juneau-petstore-client/src/assembly/bin.xml
new file mode 100644
index 0000000..ad917d5
--- /dev/null
+++ b/juneau-petstore-client/src/assembly/bin.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ***************************************************************************************************************************
+ * 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.                                              *
+ ***************************************************************************************************************************
+-->
+
+<!--
+	This assembly is used to create the template zip file that developers use to import into Eclipse to start their
+	own projects.
+ -->
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+	<id>bin</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+	<baseDirectory>/</baseDirectory>
+	<includeBaseDirectory>true</includeBaseDirectory>
+	<fileSets>
+		<fileSet>
+			<directory>${basedir}/../juneau-examples-petstore-client</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+				<include>files/**</include>
+				<include>.settings/**</include>
+				<include>.project</include>
+				<include>*.launch</include>
+				<include>*.cfg</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}/build-overlay</directory>
+			<outputDirectory>/</outputDirectory>
+			<filtered>true</filtered>
+		</fileSet>
+	</fileSets>
+	
+</assembly>
\ No newline at end of file
diff --git a/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java b/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java
new file mode 100644
index 0000000..d005383
--- /dev/null
+++ b/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java
@@ -0,0 +1,112 @@
+// ***************************************************************************************************************************
+// * 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;
+
+import static java.text.MessageFormat.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.rest.client.*;
+
+/**
+ * Example code showing how to connect to the PetStore application using a remote proxy.
+ *
+ * <p>
+ * The remote proxy allows you to make REST calls against our REST interface through Java interface method calls.
+ */
+public class Main {
+
+	private static final JsonParser JSON_PARSER = JsonParser.create().ignoreUnknownBeanProperties().build();
+
+	public static void main(String[] args) {
+
+		// Create a RestClient with JSON serialization support.
+		try (RestClient rc = RestClient.create(SimpleJsonSerializer.class, JsonParser.class).build()) {
+
+			// Instantiate our proxy.
+			PetStore petStore = rc.getRemoteResource(PetStore.class, "http://localhost:5000");
+
+			// Print out the pets in the store.
+			Collection<Pet> pets = petStore.getPets();
+
+			// Pretty-print them to SYSOUT.
+			SimpleJson.DEFAULT_READABLE.println(pets);
+
+			// Initialize the application through REST calls.
+			init(new PrintWriter(System.out), petStore);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Initialize the petstore database by using a remote resource interface against our REST.
+	 *
+	 * @param w Console output.
+	 * @return This object (for method chaining).
+	 * @throws ParseException Malformed input encountered.
+	 * @throws IOException Thrown by client stream.
+	 */
+	public static void init(PrintWriter w, PetStore ps) throws ParseException, IOException {
+
+		for (Pet x : ps.getPets()) {
+			ps.deletePet("apiKey", x.getId());
+			w.println(format("Deleted pet:  id={0}", x.getId()));
+		}
+
+		for (Order x : ps.getOrders()) {
+			ps.deleteOrder(x.getId());
+			w.println(format("Deleted order:  id={0}", x.getId()));
+		}
+
+		for (User x : ps.getUsers()) {
+			ps.deleteUser(x.getUsername());
+			w.println(format("Deleted user:  username={0}", x.getUsername()));
+		}
+
+		for (CreatePet x : load("init/Pets.json", CreatePet[].class)) {
+			long id = ps.createPet(x);
+			w.println(format("Created pet:  id={0}, name={1}", id, x.getName()));
+		}
+
+		for (Order x : load("init/Orders.json", Order[].class)) {
+			long id = ps.placeOrder(x.getPetId(), x.getUsername());
+			w.println(format("Created order:  id={0}", id));
+		}
+
+		for (User x : load("init/Users.json", User[].class)) {
+			ps.createUser(x);
+			w.println(format("Created user:  username={0}", x.getUsername()));
+		}
+
+		w.flush();
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private static <T> T load(String fileName, Class<T> c) throws ParseException, IOException {
+		return JSON_PARSER.parse(getStream(fileName), c);
+	}
+
+	private static InputStream getStream(String fileName) {
+		return Main.class.getResourceAsStream(fileName);
+	}
+}
diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json
new file mode 100644
index 0000000..b306aa8
--- /dev/null
+++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json
@@ -0,0 +1,18 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ***************************************************************************************************************************
+
+[
+	{id:101,petId:101,shipDate:'2018-01-01',status:'PLACED'},
+	{id:102,petId:102,shipDate:'2018-01-01',status:'APPROVED'},
+	{id:103,petId:103,shipDate:'2018-01-01',status:'DELIVERED'}
+]
diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json
new file mode 100644
index 0000000..c0aa31f
--- /dev/null
+++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json
@@ -0,0 +1,24 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ***************************************************************************************************************************
+
+[
+	{species:'CAT', name:'Mr. Frisky', price:39.99, tags:['friendly'], status:'AVAILABLE'},
+	{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'},
+	{species:'RABBIT', name:'Hoppy 3', price:49.99, status:'AVAILABLE'},
+	{species:'RABBIT', name:'Hoppy 4', price:49.99, status:'AVAILABLE'},
+	{species:'FISH', name:'Gorton', price:1.99, status:'PENDING'},
+	{species:'MOUSE', name:'Hackwrench', price:4.99, status:'SOLD'},
+	{species:'SNAKE', name:'Just Snake', price:9.99, status:'SOLD'}
+]
\ No newline at end of file
diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json
new file mode 100644
index 0000000..7f02a3c
--- /dev/null
+++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json
@@ -0,0 +1,18 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ***************************************************************************************************************************
+
+[
+	{username:'mwatson',firstName:'Marie',lastName:'Watson',email:'marie.watson@fakemail.com',password:'123456',phone:'444-555-7777',userStatus:'ACTIVE'},
+	{username:'dvaughn',firstName:'Daniel',lastName:'Vaughn',email:'daniel.vaughn@test.com',password:'123456',phone:'666-777-3333',userStatus:'ACTIVE'},
+	{username:'bfuller',firstName:'Brenda',lastName:'Fuller',email:'brenda.fuller@example.com',password:'123456',phone:'777-888-3333',userStatus:'INACTIVE'}
+]
diff --git a/juneau-petstore-server/.gitignore b/juneau-petstore-server/.gitignore
new file mode 100644
index 0000000..aefe663
--- /dev/null
+++ b/juneau-petstore-server/.gitignore
@@ -0,0 +1,6 @@
+/target/
+**/.DS_Store
+.classpath
+.project
+/.settings/
+/bin/
\ No newline at end of file
diff --git a/juneau-petstore-server/juneau-examples-petstore-server.launch b/juneau-petstore-server/juneau-examples-petstore-server.launch
new file mode 100644
index 0000000..bba6035
--- /dev/null
+++ b/juneau-petstore-server/juneau-examples-petstore-server.launch
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry value="/juneau-examples-petstore-app/src/main/java/org/apache/juneau/petstore/server/App.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.juneau.petstore.server.App"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="juneau-examples-petstore-server"/>
+</launchConfiguration>
diff --git a/juneau-petstore-server/src/assembly/bin.xml b/juneau-petstore-server/src/assembly/bin.xml
new file mode 100644
index 0000000..491e69e
--- /dev/null
+++ b/juneau-petstore-server/src/assembly/bin.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ***************************************************************************************************************************
+ * 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.                                              *
+ ***************************************************************************************************************************
+-->
+
+<!--
+	This assembly is used to create the template zip file that developers use to import into Eclipse to start their
+	own projects.
+ -->
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+	<id>bin</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+	<baseDirectory>/</baseDirectory>
+	<includeBaseDirectory>true</includeBaseDirectory>
+	<fileSets>
+		<fileSet>
+			<directory>${basedir}/../juneau-examples-petstore-server</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}</directory>
+			<outputDirectory>/</outputDirectory>
+			<includes>
+				<include>src/main/**</include>
+				<include>files/**</include>
+				<include>.settings/**</include>
+				<include>.project</include>
+				<include>*.launch</include>
+				<include>*.cfg</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>${basedir}/build-overlay</directory>
+			<outputDirectory>/</outputDirectory>
+			<filtered>true</filtered>
+		</fileSet>
+	</fileSets>
+	
+</assembly>
\ No newline at end of file
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java
new file mode 100644
index 0000000..f04953b
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java
@@ -0,0 +1,34 @@
+// ***************************************************************************************************************************
+// * 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;
+
+import org.apache.juneau.rest.springboot.JuneauRestInitializer;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+/**
+ * Entry point for PetStore application.
+ */
+@SpringBootApplication
+public class App {
+
+    public static void main(String[] args) {
+        new App().start(args);
+    }
+
+    protected void start(String[] args) {
+        new SpringApplicationBuilder(App.class)
+        	.initializers(new JuneauRestInitializer(App.class)) // Needed for Juneau resources as injectible Spring beans.
+        	.run(args);
+    }
+}
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java
new file mode 100644
index 0000000..d3d7370
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java
@@ -0,0 +1,62 @@
+// ***************************************************************************************************************************
+// * 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;
+
+import org.apache.juneau.petstore.rest.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.rest.springboot.annotation.JuneauRestRoot;
+import org.springframework.boot.web.servlet.*;
+import org.springframework.context.annotation.*;
+import org.springframework.web.filter.*;
+
+@Configuration
+public class AppConfiguration {
+
+    //-----------------------------------------------------------------------------------------------------------------
+    // Services
+    //-----------------------------------------------------------------------------------------------------------------
+
+    @Bean
+    public PetStoreService petStoreService() {
+        return new PetStoreService();
+    }
+
+    //-----------------------------------------------------------------------------------------------------------------
+    // REST
+    //-----------------------------------------------------------------------------------------------------------------
+
+    @Bean
+    @JuneauRestRoot
+    public RootResources rootResources() {
+        return new RootResources();
+    }
+
+    @Bean
+    public PetStoreResource petStoreResource() {
+        return new PetStoreResource();
+    }
+
+	/**
+	 * We want to be able to consume url-encoded-form-post bodies, but HiddenHttpMethodFilter triggers the HTTP
+	 * body to be consumed.  So disable it.
+	 *
+	 * @param filter The filter.
+	 * @return Filter registration bean.
+	 */
+	@Bean
+	public FilterRegistrationBean<HiddenHttpMethodFilter> registration(HiddenHttpMethodFilter filter) {
+	    FilterRegistrationBean<HiddenHttpMethodFilter> registration = new FilterRegistrationBean<>(filter);
+	    registration.setEnabled(false);
+	    return registration;
+	}
+}
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
new file mode 100644
index 0000000..de79d12
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
@@ -0,0 +1,541 @@
+// ***************************************************************************************************************************
+// * 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.dto.swagger.ui.SwaggerUI.*;
+import static org.apache.juneau.http.HttpMethodName.*;
+import static org.apache.juneau.http.response.Ok.*;
+
+import java.util.*;
+import java.util.Map;
+
+import javax.inject.*;
+
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.petstore.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.http.exception.*;
+import org.apache.juneau.rest.helper.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.rest.widget.*;
+import org.apache.juneau.transforms.*;
+import org.apache.juneau.rest.converters.*;
+
+/**
+ * Sample Petstore application.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@RestResource(
+	path="/petstore",
+	title="Petstore application",
+	description={
+		"This is a sample server Petstore server based on the Petstore sample at Swagger.io.",
+		"You can find out more about Swagger at http://swagger.io.",
+	},
+	properties= {
+		// Resolve recursive references when showing schema info in the swagger.
+		@Property(name=SWAGGERUI_resolveRefsMaxDepth, value="99")
+	},
+	swagger=@ResourceSwagger(
+		version="1.0.0",
+		title="Swagger Petstore",
+		termsOfService="You are on your own.",
+		contact=@Contact(
+			name="Juneau Development Team",
+			email="dev@juneau.apache.org",
+			url="http://juneau.apache.org"
+		),
+		license=@License(
+			name="Apache 2.0",
+			url="http://www.apache.org/licenses/LICENSE-2.0.html"
+		),
+		externalDocs=@ExternalDocs(
+			description="Find out more about Juneau",
+			url="http://juneau.apache.org"
+		),
+		tags={
+			@Tag(
+				name="pet",
+				description="Everything about your Pets",
+				externalDocs=@ExternalDocs(
+					description="Find out more",
+					url="http://juneau.apache.org"
+				)
+			),
+			@Tag(
+				name="store",
+				description="Access to Petstore orders"
+			),
+			@Tag(
+				name="user",
+				description="Operations about user",
+				externalDocs=@ExternalDocs(
+					description="Find out more about our store",
+					url="http://juneau.apache.org"
+				)
+			)
+		}
+	),
+	staticFiles={"htdocs:/htdocs"}  // Expose static files in htdocs subpackage.
+)
+@HtmlDocConfig(
+	widgets={
+		ContentTypeMenuItem.class,
+		ThemeMenuItem.class,
+	},
+	navlinks={
+		"up: request:/..",
+		"options: servlet:/?method=OPTIONS",
+		"$W{ContentTypeMenuItem}",
+		"$W{ThemeMenuItem}",
+		"source: $C{Source/gitHub}/org/apache/juneau/petstore/rest/$R{servletClassSimple}.java"
+	},
+	head={
+		"<link rel='icon' href='$U{servlet:/htdocs/cat.png}'/>"  // Add a cat icon to the page.
+	},
+	header={
+		"<h1>$R{resourceTitle}</h1>",
+		"<h2>$R{methodSummary}</h2>",
+		"$C{PetStore/headerImage}"
+	},
+	aside={
+		"<div style='max-width:400px' class='text'>",
+		"	<p>This page shows a standard nested REST resource.</p>",
+		"	<p>It shows how different properties can be rendered on the same bean in different views.</p>",
+		"	<p>It also shows examples of HtmlRender classes and @BeanProperty(format) annotations.</p>",
+		"	<p>It also shows how the Queryable converter and query widget can be used to create searchable interfaces.</p>",
+		"</div>"
+	},
+	stylesheet="servlet:/htdocs/themes/dark.css"  // Use dark theme by default.
+)
+public class PetStoreResource extends BasicRest implements PetStore {
+
+	@Inject
+	private PetStoreService store;
+
+	/**
+	 * Navigation page
+	 *
+	 * @return Navigation page contents.
+	 */
+	@RestMethod(
+		name=GET,
+		path="/",
+		summary="Navigation page"
+	)
+	@HtmlDocConfig(
+		style={
+			"INHERIT",  // Flag for inheriting resource-level CSS.
+			"body { ",
+				"background-image: url('petstore/htdocs/background.jpg'); ",
+				"background-color: black; ",
+				"background-size: cover; ",
+				"background-attachment: fixed; ",
+			"}"
+		}
+	)
+	public ResourceDescriptions getTopPage() {
+		return new ResourceDescriptions()
+			.append("pet", "All pets in the store")
+			.append("store", "Orders and inventory")
+			.append("user", "Petstore users")
+		;
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	// Pets
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=GET,
+		path="/pet",
+		summary="All pets in the store",
+		swagger=@MethodSwagger(
+			tags="pet",
+			parameters={
+				Queryable.SWAGGER_PARAMS
+			}
+		),
+		converters={Queryable.class}
+	)
+	@BeanConfig(
+		bpx="Pet: tags,photo"
+	)
+	public Collection<Pet> getPets() throws NotAcceptable {
+		return store.getPets();
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=GET,
+		path="/pet/{petId}",
+		summary="Find pet by ID",
+		description="Returns a single pet",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[ { api_key:[] } ]"
+			}
+		)
+	)
+	public Pet getPet(long petId) throws IdNotFound, NotAcceptable {
+		return store.getPet(petId);
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=POST,
+		path="/pet",
+		summary="Add a new pet to the store",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[ { petstore_auth:['write:pets','read:pets'] } ]"
+			}
+		)
+	)
+	public long createPet(CreatePet pet) throws IdConflict, NotAcceptable, UnsupportedMediaType {
+		return store.create(pet).getId();
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=PUT,
+		path="/pet/{petId}",
+		summary="Update an existing pet",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[ { petstore_auth: ['write:pets','read:pets'] } ]"
+			}
+		)
+	)
+	public Ok updatePet(UpdatePet pet) throws IdNotFound, NotAcceptable, UnsupportedMediaType {
+		store.update(pet);
+		return OK;
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=GET,
+		path="/pet/findByStatus",
+		summary="Finds Pets by status",
+		description="Multiple status values can be provided with comma separated strings.",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[{petstore_auth:['write:pets','read:pets']}]"
+			}
+		)
+	)
+	public Collection<Pet> findPetsByStatus(PetStatus[] status) throws NotAcceptable {
+		return store.getPetsByStatus(status);
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=GET,
+		path="/pet/findByTags",
+		summary="Finds Pets by tags",
+		description="Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"
+			}
+		)
+	)
+	@Deprecated
+	public Collection<Pet> findPetsByTags(String[] tags) throws InvalidTag, NotAcceptable {
+		return store.getPetsByTags(tags);
+	}
+
+	@Override /* PetStore */
+	@RestMethod(
+		name=DELETE,
+		path="/pet/{petId}",
+		summary="Deletes a pet",
+		swagger=@MethodSwagger(
+			tags="pet",
+			value={
+				"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"
+			}
+		)
+	)
+	public Ok deletePet(String apiKey, long petId) throws IdNotFound, NotAcceptable {
+		store.removePet(petId);
+		return OK;
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	// Orders
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Store navigation page.
+	 *
+	 * @return Store navigation page contents.
+	 */
+	@RestMethod(
+		summary="Store navigation page",
+		swagger=@MethodSwagger(
+			tags="store"
+		)
+	)
+	public ResourceDescriptions getStore() {
+		return new ResourceDescriptions()
+			.append("store/order", "Petstore orders")
+			.append("store/inventory", "Petstore inventory")
+		;
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/store/order",
+		summary="Petstore orders",
+		swagger=@MethodSwagger(
+			tags="store"
+		)
+	)
+	@HtmlDocConfig(
+		widgets={
+			QueryMenuItem.class
+		},
+		navlinks={
+			"INHERIT",                // Inherit links from class.
+			"[2]:$W{QueryMenuItem}",  // Insert QUERY link in position 2.
+			"[3]:$W{AddOrderMenuItem}"  // Insert ADD link in position 3.
+		}
+	)
+	public Collection<Order> getOrders() throws NotAcceptable {
+		return store.getOrders();
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/store/order/{orderId}",
+		summary="Find purchase order by ID",
+		description="Returns a purchase order by ID.",
+		swagger=@MethodSwagger(
+			tags="store"
+		)
+	)
+	public Order getOrder(long orderId) throws InvalidId, IdNotFound, NotAcceptable {
+		if (orderId < 1 || orderId > 1000)
+			throw new InvalidId();
+		return store.getOrder(orderId);
+	}
+
+	@Override
+	@RestMethod(
+		name=POST,
+		path="/store/order",
+		summary="Place an order for a pet",
+		swagger=@MethodSwagger(
+			tags="store"
+		),
+		pojoSwaps={
+			TemporalDateSwap.IsoLocalDate.class
+		}
+	)
+	public long placeOrder(long petId, String username) throws IdConflict, NotAcceptable, UnsupportedMediaType {
+		CreateOrder co = new CreateOrder(petId, username);
+		return store.create(co).getId();
+	}
+
+	@Override
+	@RestMethod(
+		name=DELETE,
+		path="/store/order/{orderId}",
+		summary="Delete purchase order by ID",
+		description= {
+			"For valid response try integer IDs with positive integer value.",
+			"Negative or non-integer values will generate API errors."
+		},
+		swagger=@MethodSwagger(
+			tags="store"
+		)
+	)
+	public Ok deleteOrder(long orderId) throws InvalidId, IdNotFound, NotAcceptable {
+		if (orderId < 0)
+			throw new InvalidId();
+		store.removeOrder(orderId);
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/store/inventory",
+		summary="Returns pet inventories by status",
+		description="Returns a map of status codes to quantities",
+		swagger=@MethodSwagger(
+			tags="store",
+			responses={
+				"200:{ 'x-example':{AVAILABLE:123} }",
+			},
+			value={
+				"security:[ { api_key:[] } ]"
+			}
+		)
+	)
+	public Map<PetStatus,Integer> getStoreInventory() throws NotAcceptable {
+		return store.getInventory();
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	// Users
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/user",
+		summary="Petstore users",
+		bpx="User: email,password,phone",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Collection<User> getUsers() throws NotAcceptable {
+		return store.getUsers();
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/user/{username}",
+		summary="Get user by user name",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public User getUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable {
+		return store.getUser(username);
+	}
+
+	@Override
+	@RestMethod(
+		name=POST,
+		path="/user",
+		summary="Create user",
+		description="This can only be done by the logged in user.",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok createUser(User user) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
+		store.create(user);
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=POST,
+		path="/user/createWithArray",
+		summary="Creates list of users with given input array",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok createUsers(User[] users) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
+		for (User user : users)
+			store.create(user);
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=PUT,
+		path="/user/{username}",
+		summary="Update user",
+		description="This can only be done by the logged in user.",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok updateUser(String username, User user) throws InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType {
+		store.update(user);
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=DELETE,
+		path="/user/{username}",
+		summary="Delete user",
+		description="This can only be done by the logged in user.",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok deleteUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable {
+		store.removeUser(username);
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/user/login",
+		summary="Logs user into the system",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok login(
+			String username,
+			String password,
+			Value<Integer> rateLimit,
+			Value<ExpiresAfter> expiresAfter
+		) throws InvalidLogin, NotAcceptable {
+
+		RestRequest req = getRequest();
+
+		if (! store.isValid(username, password))
+			throw new InvalidLogin();
+
+		Date d = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
+		req.getSession().setAttribute("login-expires", d);
+		rateLimit.set(1000);
+		expiresAfter.set(new ExpiresAfter(d));
+		return OK;
+	}
+
+	@Override
+	@RestMethod(
+		name=GET,
+		path="/user/logout",
+		summary="Logs out current logged in user session",
+		swagger=@MethodSwagger(
+			tags="user"
+		)
+	)
+	public Ok logout() throws NotAcceptable {
+		getRequest().getSession().removeAttribute("login-expires");
+		return OK;
+	}
+}
\ No newline at end of file
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java
new file mode 100644
index 0000000..a92d9de
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java
@@ -0,0 +1,66 @@
+// ***************************************************************************************************************************
+// * 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.html.annotation.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.widget.*;
+import org.apache.juneau.serializer.annotation.*;
+
+/**
+ * Sample REST resource showing how to implement a "router" resource page.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+@RestResource(
+	path="/*",
+	title="Root resources",
+	description="Example of a router resource page.",
+	children={
+		PetStoreResource.class
+	}
+)
+@HtmlDocConfig(
+	widgets={
+		ContentTypeMenuItem.class,
+		ThemeMenuItem.class
+	},
+	navlinks={
+		"options: ?method=OPTIONS",
+		"$W{ContentTypeMenuItem}",
+		"$W{ThemeMenuItem}",
+		"source: $C{Source/gitHub}/org/apache/juneau/petstore/rest/$R{servletClassSimple}.java"
+	},
+	aside={
+		"<div style='max-width:400px' class='text'>",
+		"	<p>This is an example of a 'router' page that serves as a jumping-off point to child resources.</p>",
+		"	<p>Resources can be nested arbitrarily deep through router pages.</p>",
+		"	<p>Note the <span class='link'>options</span> link provided that lets you see the generated swagger doc for this page.</p>",
+		"	<p>Also note the <span class='link'>sources</span> link on these pages to view the source code for the page.</p>",
+		"	<p>All content on pages in the UI are serialized POJOs.  In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.</p>",
+		"	<p>Other features (such as this aside) are added through annotations.</p>",
+		"</div>"
+	}
+)
+@SerializerConfig(
+	// For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
+	// String comparisons.
+	// You can apply any of the Serializer/Parser/BeanContext settings this way.
+	quoteChar="'"
+)
+public class RootResources extends BasicRestServletGroup {
+	private static final long serialVersionUID = 1L;
+}
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java
new file mode 100644
index 0000000..4e2aedf
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java
@@ -0,0 +1,273 @@
+// ***************************************************************************************************************************
+// * 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.service;
+
+import java.util.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.pojotools.*;
+
+/**
+ * Superclass for DAOs that use the JPA entity manager.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+public class AbstractPersistenceService {
+
+	private final EntityManagerFactory entityManagerFactory;
+
+	/**
+	 * Constructor.
+	 */
+	public AbstractPersistenceService() {
+		entityManagerFactory = Persistence.createEntityManagerFactory("test");
+	}
+
+	/**
+	 * Retrieves an entity manager session.
+	 *
+	 * @return The entity manager session.
+	 */
+	protected EntityManager getEntityManager() {
+		return entityManagerFactory.createEntityManager();
+	}
+
+	/**
+	 * Retrieves the specified JPA bean from the repository.
+	 *
+	 * @param em The entity manager to use to retrieve the bean.
+	 * @param t The bean type to retrieve.
+	 * @param id The primary key value.
+	 * @return The JPA bean, or null if not found.
+	 */
+	protected <T> T find(EntityManager em, Class<T> t, Object id) {
+		return em.find(t, id);
+	}
+
+	/**
+	 * Same as {@link #find(EntityManager, Class, Object)} but uses a new entity manager.
+	 *
+	 * @param t The bean type to retrieve.
+	 * @param id The primary key value.
+	 * @return The JPA bean, or null if not found.
+	 */
+	protected <T> T find(Class<T> t, Object id) {
+		return find(getEntityManager(), t, id);
+	}
+
+	/**
+	 * Store the specified JPA bean in the repository.
+	 *
+	 * @param em The entity manager to use to store and merge the bean.
+	 * @param t The bean to store.
+	 * @return The merged JPA bean returned by the {@link EntityManager#merge(Object)} method, or null if the bean was null.
+	 */
+	protected <T> T merge(EntityManager em, T t) {
+		if (t == null)
+			return null;
+		try {
+			EntityTransaction et = em.getTransaction();
+			et.begin();
+			t = em.merge(t);
+			et.commit();
+			return t;
+		} finally {
+			em.close();
+		}
+	}
+
+	/**
+	 * Same as {@link #merge(EntityManager, Object)} but uses a new entity manager.
+	 *
+	 * @param t The bean to store.
+	 * @return The merged JPA bean returned by the {@link EntityManager#merge(Object)} method, or null if the bean was null.
+	 */
+	protected <T> T merge(T t) {
+		return merge(getEntityManager(), t);
+	}
+
+	/**
+	 * Store the specified JPA beans in the repository.
+	 *
+	 * All values are persisted in the same transaction.
+	 *
+	 * @param em The entity manager to use to store and merge the beans.
+	 * @param c The collection of beans to store.
+	 * @return The merged JPA beans returned by the {@link EntityManager#merge(Object)} method.
+	 */
+	protected <T> Collection<T> merge(EntityManager em, Collection<T> c) {
+		Collection<T> c2 = new ArrayList<>();
+		try {
+			EntityTransaction et = em.getTransaction();
+			et.begin();
+			for (T t : c)
+				c2.add(em.merge(t));
+			et.commit();
+			return c2;
+		} finally {
+			em.close();
+		}
+	}
+
+	/**
+	 * Same as {@link #merge(EntityManager, Collection)} but uses a new entity manager.
+	 *
+	 * @param c The collection of beans to store.
+	 * @return The merged JPA beans returned by the {@link EntityManager#merge(Object)} method.
+	 */
+	protected <T> Collection<T> merge(Collection<T> c) {
+		return merge(getEntityManager(), c);
+	}
+
+	/**
+	 * Remove the specified JPA bean from the repository.
+	 *
+	 * @param t The bean type to remove.
+	 * @param id The primary key value.
+	 */
+	protected <T> void remove(Class<T> t, Object id) {
+		EntityManager em = getEntityManager();
+		remove(em, find(em, t, id));
+	}
+
+	/**
+	 * Remove the specified JPA bean from the repository.
+	 *
+	 * @param em The entity manager used to retrieve the bean.
+	 * @param t The bean to remove.  Can be null.
+	 */
+	protected <T> void remove(EntityManager em, T t) {
+		if (t == null)
+			return;
+		try {
+			EntityTransaction et = em.getTransaction();
+			et.begin();
+			em.remove(t);
+			et.commit();
+		} finally {
+			em.close();
+		}
+	}
+
+	/**
+	 * Runs a JPA query and returns the results.
+	 *
+	 * @param <T> The bean type.
+	 * @param em The entity manager to use to retrieve the beans.
+	 * @param query The JPA query.
+	 * @param t The bean type.
+	 * @param searchArgs Optional search arguments.
+	 * @return The results.
+	 */
+	protected <T> List<T> query(EntityManager em, String query, Class<T> t, SearchArgs searchArgs, PageArgs pageArgs) {
+		TypedQuery<T> q = em.createQuery(query, t);
+		if (pageArgs != null) {
+			q.setMaxResults(pageArgs.getLimit() == 0 ? 100 : pageArgs.getLimit());
+			q.setFirstResult(pageArgs.getPosition());
+		}
+		return em.createQuery(query, t).getResultList();
+	}
+
+	/**
+	 * Same as {@link #query(EntityManager,String,Class,SearchArgs)} but uses a new entity manager.
+	 *
+	 * @param <T> The bean type.
+	 * @param query The JPA query.
+	 * @param t The bean type.
+	 * @param searchArgs Optional search arguments.
+	 * @return The results.
+	 */
+	protected <T> List<T> query(String query, Class<T> t, SearchArgs searchArgs, PageArgs pageArgs) {
+		return query(getEntityManager(), query, t, searchArgs, pageArgs);
+	}
+
+	/**
+	 * Runs a JPA parameterized query and returns the results.
+	 *
+	 * @param em The entity manager to use to retrieve the beans.
+	 * @param query The JPA query.
+	 * @param t The bean type.
+	 * @param params The query parameter values.
+	 * @return The results.
+	 */
+	protected <T> List<T> query(EntityManager em, String query, Class<T> t, Map<String,Object> params) {
+		TypedQuery<T> tq = em.createQuery(query, t);
+		for (Map.Entry<String,Object> e : params.entrySet()) {
+			tq.setParameter(e.getKey(), e.getValue());
+		}
+		return tq.getResultList();
+	}
+
+	/**
+	 * Same as {@link #query(EntityManager,String,Class,Map)} but uses a new entity manager.
+	 *
+	 * @param query The JPA query.
+	 * @param t The bean type.
+	 * @param params The query parameter values.
+	 * @return The results.
+	 */
+	protected <T> List<T> query(String query, Class<T> t, Map<String,Object> params) {
+		return query(getEntityManager(), query, t, params);
+	}
+
+	/**
+	 * Runs a JPA update statement.
+	 *
+	 * @param em The entity manager to use to run the statement.
+	 * @param query The JPA update statement.
+	 * @return The number of rows modified.
+	 */
+	protected int update(EntityManager em, String query) {
+		return em.createQuery(query).executeUpdate();
+	}
+
+	/**
+	 * Same as {@link #update(EntityManager,String)} but uses a new entity manager.
+	 *
+	 * @param query The JPA update statement.
+	 * @return The number of rows modified.
+	 */
+	protected int update(String query) {
+		return update(getEntityManager(), query);
+	}
+
+	/**
+	 * Runs a JPA parameterized update statement.
+	 *
+	 * @param em The entity manager to use to run the statement.
+	 * @param query The JPA update statement.
+	 * @param params The query parameter values.
+	 * @return The number of rows modified.
+	 */
+	protected int update(EntityManager em, String query, Map<String,Object> params) {
+		Query q = em.createQuery(query);
+		for (Map.Entry<String,Object> e : params.entrySet()) {
+			q.setParameter(e.getKey(), e.getValue());
+		}
+		return q.executeUpdate();
+	}
+
+	/**
+	 * Same as {@link #update(EntityManager,String,Map)} but uses a new entity manager.
+	 *
+	 * @param query The JPA update statement.
+	 * @param params The query parameter values.
+	 * @return The number of rows modified.
+	 */
+	protected int update(String query, Map<String,Object> params) {
+		return update(getEntityManager(), query, params);
+	}
+}
diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java
new file mode 100644
index 0000000..ac83c4c
--- /dev/null
+++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java
@@ -0,0 +1,329 @@
+// ***************************************************************************************************************************
+// * 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.service;
+
+import static java.text.MessageFormat.*;
+
+import java.io.*;
+import java.util.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.pojotools.*;
+import org.apache.juneau.pojotools.SearchArgs;
+
+/**
+ * Pet store database application.
+ * <p>
+ * Uses JPA persistence to store and retrieve PetStore DTOs.
+ * JPA beans are defined in <c>META-INF/persistence.xml</c>.
+ *
+ * <ul class='seealso'>
+ * 	<li class='extlink'>{@source}
+ * </ul>
+ */
+public class PetStoreService extends AbstractPersistenceService {
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Initialization methods.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Initialize the petstore database using JPA.
+	 *
+	 * @param w Console output.
+	 * @return This object (for method chaining).
+	 * @throws ParseException Malformed input encountered.
+	 * @throws IOException File could not be read from file system.
+	 */
+	public PetStoreService initDirect(PrintWriter w) throws ParseException, IOException {
+
+		EntityManager em = getEntityManager();
+		EntityTransaction et = em.getTransaction();
+		JsonParser parser = JsonParser.create().build();
+
+		et.begin();
+
+		for (Pet x : em.createQuery("select X from PetstorePet X", Pet.class).getResultList()) {
+			em.remove(x);
+			w.println(format("Deleted pet:  id={0}", x.getId()));
+		}
+		for (Order x : em.createQuery("select X from PetstoreOrder X", Order.class).getResultList()) {
+			em.remove(x);
+			w.println(format("Deleted order:  id={0}", x.getId()));
+		}
+		for (User x : em.createQuery("select X from PetstoreUser X", User.class).getResultList()) {
+			em.remove(x);
+			w.println(format("Deleted user:  username={0}", x.getUsername()));
+		}
+
+		et.commit();
+		et.begin();
+
+		for (Pet x : parser.parse(getStream("init/Pets.json"), Pet[].class)) {
+			x = em.merge(x);
+			w.println(format("Created pet:  id={0}, name={1}", x.getId(), x.getName()));
+		}
+		for (Order x : parser.parse(getStream("init/Orders.json"), Order[].class)) {
+			x = em.merge(x);
+			w.println(format("Created order:  id={0}", x.getId()));
+		}
+		for (User x: parser.parse(getStream("init/Users.json"), User[].class)) {
+			x = em.merge(x);
+			w.println(format("Created user:  username={0}", x.getUsername()));
+		}
+
+		et.commit();
+
+		return this;
+	}
+
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Service methods.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns the pet with the specified ID.
+	 *
+	 * @param id The pet ID.
+	 * @return The pet with the specified ID.  Never <jk>null</jk>.
+	 * @throws IdNotFound If pet was not found.
+	 */
+	public Pet getPet(long id) throws IdNotFound {
+		return find(Pet.class, id);
+	}
+
+	/**
+	 * Returns the order with the specified ID.
+	 *
+	 * @param id The order ID.
+	 * @return The order with the specified ID.  Never <jk>null</jk>.
+	 * @throws IdNotFound If order was not found.
+	 */
+	public Order getOrder(long id) throws IdNotFound {
+		return find(Order.class, id);
+	}
+
+	/**
+	 * Returns the user with the specified username.
+	 *
+	 * @param username The username.
+	 * @return The user with the specified username.  Never <jk>null</jk>.
+	 * @throws InvalidUsername Username was not valid.
+	 * @throws IdNotFound If order was not found.
+	 */
+	public User getUser(String username) throws InvalidUsername, IdNotFound  {
+		assertValidUsername(username);
+		return find(User.class, username);
+	}
+
+	/**
+	 * Returns all pets in the database.
+	 *
+	 * @return All pets in the database.
+	 */
+	public List<Pet> getPets() {
+		return query("select X from PetstorePet X", Pet.class, (SearchArgs)null, (PageArgs)null);
+	}
+
+	/**
+	 * Returns all orders in the database.
+	 *
+	 * @return All orders in the database.
+	 */
+	public List<Order> getOrders() {
+		return query("select X from PetstoreOrder X", Order.class, (SearchArgs)null, (PageArgs)null);
+	}
+
+	/**
+	 * Returns all users in the database.
+	 *
+	 * @return All users in the database.
+	 */
+	public List<User> getUsers() {
+		return query("select X from PetstoreUser X", User.class, (SearchArgs)null, (PageArgs)null);
+	}
+
+	/**
+	 * Creates a new pet in the database.
+	 *
+	 * @param c The pet input data.
+	 * @return a new {@link Pet} object.
+	 */
+	public Pet create(CreatePet c) {
+		return merge(new Pet().status(PetStatus.AVAILABLE).apply(c));
+	}
+
+	/**
+	 * Creates a new order in the database.
+	 *
+	 * @param c The order input data.
+	 * @return a new {@link Order} object.
+	 */
+	public Order create(CreateOrder c) {
+		return merge(new Order().status(OrderStatus.PLACED).apply(c));
+	}
+
+	/**
+	 * Creates a new user in the database.
+	 *
+	 * @param c The user input data.
+	 * @return a new {@link User} object.
+	 */
+	public User create(User c) {
+		return merge(new User().apply(c));
+	}
+
+	/**
+	 * Updates a pet in the database.
+	 *
+	 * @param u The update information.
+	 * @return The updated {@link Pet} object.
+	 * @throws IdNotFound Pet was not found.
+	 */
+	public Pet update(UpdatePet u) throws IdNotFound {
+		EntityManager em = getEntityManager();
+		return merge(em, find(em, Pet.class, u.getId()).apply(u));
+	}
+
+	/**
+	 * Updates an order in the database.
+	 *
+	 * @param o The update information.
+	 * @return The updated {@link Order} object.
+	 * @throws IdNotFound Order was not found.
+	 */
+	public Order update(Order o) throws IdNotFound {
+		EntityManager em = getEntityManager();
+		return merge(em, find(em, Order.class, o.getId()).apply(o));
+	}
+
+	/**
+	 * Updates a user in the database.
+	 *
+	 * @param u The update information.
+	 * @return The updated {@link User} object.
+	 * @throws IdNotFound User was not found.
+	 * @throws InvalidUsername The username was not valid.
+	 */
+	public User update(User u) throws IdNotFound, InvalidUsername {
+		assertValidUsername(u.getUsername());
+		EntityManager em = getEntityManager();
+		return merge(em, find(em, User.class, u.getUsername()).apply(u));
+	}
+
+	/**
+	 * Removes a pet from the database.
+	 *
+	 * @param id The pet ID.
+	 * @throws IdNotFound Pet was not found.
+	 */
+	public void removePet(long id) throws IdNotFound {
+		EntityManager em = getEntityManager();
+		remove(em, find(em, Pet.class, id));
+	}
+
+	/**
+	 * Removes an order from the database.
+	 *
+	 * @param id The order ID.
+	 * @throws IdNotFound Order was not found.
+	 */
+	public void removeOrder(long id) throws IdNotFound {
+		EntityManager em = getEntityManager();
+		remove(em, find(em, Order.class, id));
+	}
+
+	/**
+	 * Removes a user from the database.
+	 *
+	 * @param username The username.
+	 * @throws IdNotFound User was not found.
+	 */
+	public void removeUser(String username) throws IdNotFound {
+		EntityManager em = getEntityManager();
+		remove(em, find(em, User.class, username));
+	}
+
+	/**
+	 * Returns all pets with the specified statuses.
+	 *
+	 * @param status Pet statuses.
+	 * @return Pets with the specified statuses.
+	 */
+	public Collection<Pet> getPetsByStatus(PetStatus[] status) {
+		return getEntityManager()
+			.createQuery("select X from PetstorePet X where X.status in :status", Pet.class)
+			.setParameter("status", status)
+			.getResultList();
+	}
+
+	/**
+	 * Returns all pets with the specified tags.
+	 *
+	 * @param tags Pet tags.
+	 * @return Pets with the specified tags.
+	 * @throws InvalidTag Tag name was invalid.
+	 */
+	public Collection<Pet> getPetsByTags(String[] tags) throws InvalidTag {
+		return getEntityManager()
+			.createQuery("select X from PetstorePet X where X.tags in :tags", Pet.class)
+			.setParameter("tags", tags)
+			.getResultList();
+	}
+
+	/**
+	 * Returns a summary of pet statuses and counts.
+	 *
+	 * @return A summary of pet statuses and counts.
+	 */
+	public Map<PetStatus,Integer> getInventory() {
+		Map<PetStatus,Integer> m = new LinkedHashMap<>();
+		for (Pet p : getPets()) {
+			PetStatus ps = p.getStatus();
+			if (! m.containsKey(ps))
+				m.put(ps, 1);
+			else
+				m.put(ps, m.get(ps) + 1);
+		}
+		return m;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified username and password is valid.
+	 *
+	 * @param username The username.
+	 * @param password The password.
+	 * @return <jk>true</jk> if the specified username and password is valid.
+	 */
+	public boolean isValid(String username, String password) {
+		return getUser(username).getPassword().equals(password);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private void assertValidUsername(String username) throws InvalidUsername {
+		if (username == null || ! username.matches("[\\w\\d]{3,8}"))
+			throw new InvalidUsername();
+	}
+
+	private InputStream getStream(String fileName) {
+		return getClass().getResourceAsStream(fileName);
+	}
+}
\ No newline at end of file
diff --git a/juneau-petstore-server/src/main/resources/META-INF/persistence.xml b/juneau-petstore-server/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..8db6a41
--- /dev/null
+++ b/juneau-petstore-server/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,34 @@
+<!--
+ ***************************************************************************************************************************
+ * 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.                                              *
+ ***************************************************************************************************************************
+-->
+<persistence
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+	version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
+	<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
+		<class>org.apache.juneau.petstore.dto.Pet</class>
+		<class>org.apache.juneau.petstore.dto.Order</class>
+		<class>org.apache.juneau.petstore.dto.User</class>
+		<properties>
+			<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+			<property name="javax.persistence.jdbc.url" value="jdbc:derby:target/derby/testDB;create=true" />
+			<property name="javax.persistence.jdbc.user" value="" />
+			<property name="javax.persistence.jdbc.password" value="" />
+			<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
+			<property name="hibernate.hbm2ddl.auto" value="create-drop" />
+			<property name="show_sql" value="true" />
+			<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
+		</properties>
+	</persistence-unit>
+</persistence>
\ No newline at end of file
diff --git a/juneau-petstore-server/src/main/resources/application.properties b/juneau-petstore-server/src/main/resources/application.properties
new file mode 100644
index 0000000..768c87b
--- /dev/null
+++ b/juneau-petstore-server/src/main/resources/application.properties
@@ -0,0 +1,15 @@
+// ***************************************************************************************************************************
+// * 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.                                              *
+// ****************************************************************************************************************************
+
+logging.level.org.springframework=INFO
+server.port=5000
diff --git a/juneau-petstore-server/src/main/resources/htdocs/background.jpg b/juneau-petstore-server/src/main/resources/htdocs/background.jpg
new file mode 100644
index 0000000..d75bcf1
Binary files /dev/null and b/juneau-petstore-server/src/main/resources/htdocs/background.jpg differ
diff --git a/juneau-petstore-server/src/main/resources/htdocs/cat.png b/juneau-petstore-server/src/main/resources/htdocs/cat.png
new file mode 100644
index 0000000..917abc6
Binary files /dev/null and b/juneau-petstore-server/src/main/resources/htdocs/cat.png differ
diff --git a/juneau-petstore-server/src/main/resources/juneau.cfg b/juneau-petstore-server/src/main/resources/juneau.cfg
new file mode 100755
index 0000000..98e4574
--- /dev/null
+++ b/juneau-petstore-server/src/main/resources/juneau.cfg
@@ -0,0 +1,70 @@
+# ***************************************************************************************************************************
+# * 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.                                              *
+# ***************************************************************************************************************************
+
+#=======================================================================================================================
+# REST settings
+#=======================================================================================================================
+[REST]
+
+# Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @RestResource-annotated
+# classes.  These are static files that are served up by the servlet under the specified sub-paths.
+# For example, given the following setting...
+# 	staticFiles = htdocs:my-docs,styles/my-styles
+# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
+# This path can be relative to the working directory, classpath root, or package of your resource class.
+# Used by the BasicRestConfig interface that defines the following value:
+# 	staticFiles="$C{REST/staticFiles}"
+staticFiles = htdocs:htdocs
+
+# Stylesheet to use for HTML views.
+# Used by the BasicRestConfig interface that defines the following value:
+# 	stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"
+theme = servlet:/htdocs/themes/devops.css
+
+# Various look-and-feel settings used in the BasicRestConfig interface.
+headerIcon = servlet:/htdocs/images/juneau.png
+headerLink = http://juneau.apache.org
+footerIcon = servlet:/htdocs/images/asf.png
+footerLink = http://www.apache.org
+favicon = $C{REST/headerIcon}
+head = <link rel='icon' href='$U{$C{REST/favicon}}'/>
+header = 
+	<a href='$U{$C{REST/headerLink}}'>
+		<img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/>
+	</a>
+footer = 
+	<a href='$U{$C{REST/footerLink}}'>
+		<img style='float:right;padding-right:20px;height:32px' src='$U{$C{REST/footerIcon}}'>
+	</a>
+
+#=======================================================================================================================
+# SqlQueryResource properties
+#=======================================================================================================================
+[SqlQueryResource]
+driver = org.apache.derby.jdbc.EmbeddedDriver
+directory = target/derby/testDB
+connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true
+allowTempUpdates = true
+includeRowNums = false
+
+#=======================================================================================================================
+# Source code location
+#=======================================================================================================================
+[Source]
+gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java
+
+#=======================================================================================================================
+# PetStoreResource properties
+#=======================================================================================================================
+[PetStore]
+headerImage = <a href='http://swagger.io'><img src='$U{servlet:/htdocs/cat.png}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>
diff --git a/juneau-petstore-server/src/main/resources/log4j.xml b/juneau-petstore-server/src/main/resources/log4j.xml
new file mode 100644
index 0000000..18b0d7c
--- /dev/null
+++ b/juneau-petstore-server/src/main/resources/log4j.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ***************************************************************************************************************************
+ * 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.                                              *
+ ***************************************************************************************************************************
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+    <appender name="console" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
+        </layout>
+    </appender>
+
+    <root>
+        <priority value="INFO"/>
+        <appender-ref ref="console"/>
+    </root>
+
+</log4j:configuration>
\ No newline at end of file