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

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


The following commit(s) were added to refs/heads/master by this push:
     new 1cd1481c5 OpenAPI v3 improvements.
1cd1481c5 is described below

commit 1cd1481c563aded201c4f3d6ab5a64d633b770b4
Author: James Bognar <[email protected]>
AuthorDate: Tue Sep 30 11:53:40 2025 -0400

    OpenAPI v3 improvements.
---
 .../apache/juneau/bean/openapi/ui/OpenApiUI.java   | 416 +++++++++++++++++++++
 .../juneau/bean/openapi/ui/package-info.java       |  29 +-
 .../org/apache/juneau/bean/openapi3/Callback.java  |  87 +++--
 .../apache/juneau/bean/openapi3/Components.java    | 245 ++++++++++++
 .../apache/juneau/bean/openapi3/HeaderInfo.java    |   8 +-
 .../org/apache/juneau/bean/openapi3/Items.java     |  22 +-
 .../org/apache/juneau/bean/openapi3/OpenApi.java   | 281 ++++++++++++++
 .../juneau/bean/openapi3/OpenApiBuilder.java       | 302 +++++++++++++++
 .../org/apache/juneau/bean/openapi3/Operation.java | 309 +++++++++++++++
 .../org/apache/juneau/bean/openapi3/Parameter.java | 320 ++++++++++++++++
 .../org/apache/juneau/bean/openapi3/PathItem.java  | 303 +++++++++++++++
 .../apache/juneau/bean/openapi3/SchemaInfo.java    |  14 +-
 .../juneau/bean/openapi3/SecurityRequirement.java  |  83 ++++
 .../juneau/a/rttests/DTOs_RoundTripTest.java       |   1 -
 .../apache/juneau/{dto => bean}/atom/AtomTest.java |   3 +-
 .../juneau/{dto => bean}/html5/Html5BasicTest.java |   3 +-
 .../html5/Html5Template_ComboRoundTripTest.java    |   3 +-
 .../html5/Html5_ComboRoundTripTest.java            |   4 +-
 .../{dto => bean}/jsonschema/JsonSchema_Test.java  |   3 +-
 .../juneau/{dto => bean}/swagger/Contact_Test.java |   3 +-
 .../swagger/ExternalDocumentation_Test.java        |   3 +-
 .../{dto => bean}/swagger/HeaderInfo_Test.java     |   3 +-
 .../juneau/{dto => bean}/swagger/Info_Test.java    |   3 +-
 .../juneau/{dto => bean}/swagger/Items_Test.java   |   3 +-
 .../juneau/{dto => bean}/swagger/License_Test.java |   3 +-
 .../{dto => bean}/swagger/Operation_Test.java      |   3 +-
 .../{dto => bean}/swagger/ParameterInfo_Test.java  |   3 +-
 .../{dto => bean}/swagger/ResponseInfo_Test.java   |   3 +-
 .../{dto => bean}/swagger/SchemaInfo_Test.java     |   3 +-
 .../{dto => bean}/swagger/SecurityScheme_Test.java |   3 +-
 .../{dto => bean}/swagger/SwaggerBuilder_Test.java |   3 +-
 .../juneau/{dto => bean}/swagger/Swagger_Test.java |   4 +-
 .../juneau/{dto => bean}/swagger/Tag_Test.java     |   3 +-
 .../juneau/{dto => bean}/swagger/Xml_Test.java     |   3 +-
 34 files changed, 2368 insertions(+), 114 deletions(-)

diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/OpenApiUI.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/OpenApiUI.java
new file mode 100644
index 000000000..26c388229
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/OpenApiUI.java
@@ -0,0 +1,416 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi.ui;
+
+import static java.util.Collections.*;
+import static org.apache.juneau.bean.html5.HtmlBuilder.*;
+import static org.apache.juneau.common.internal.Utils.set;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.bean.html5.*;
+import org.apache.juneau.bean.openapi3.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.common.internal.*;
+import org.apache.juneau.cp.*;
+import org.apache.juneau.swap.*;
+
+/**
+ * Generates an OpenAPI-UI interface from an OpenAPI document.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../../index.html#jd.OpenApiUi">Overview &gt; juneau-dto &gt; 
OpenAPI UI</a>
+ * </ul>
+ */
+public class OpenApiUI extends ObjectSwap<OpenApi,Div> {
+
+       static final FileFinder RESOURCES = FileFinder
+               .create(BeanStore.INSTANCE)
+               .cp(OpenApiUI.class, null, true)
+               .dir(",")
+               
.caching(Boolean.getBoolean("RestContext.disableClasspathResourceCaching.b") ? 
-1 : 1_000_000)
+               .build();
+
+       private static final Set<String> STANDARD_METHODS = set("get", "put", 
"post", "delete", "options", "head", "patch", "trace");
+
+       /**
+        * This UI applies to HTML requests only.
+        */
+       @Override
+       public org.apache.juneau.MediaType[] forMediaTypes() {
+               return new org.apache.juneau.MediaType[] 
{org.apache.juneau.MediaType.HTML};
+       }
+
+       private static final class Session {
+               final int resolveRefsMaxDepth;
+               final OpenApi openApi;
+
+               Session(OpenApi openApi) {
+                       this.openApi = openApi.copy();
+                       this.resolveRefsMaxDepth = 1;
+               }
+       }
+
+       @Override
+       public Div swap(BeanSession beanSession, OpenApi openApi) throws 
Exception {
+
+               var s = new Session(openApi);
+
+               var css = 
RESOURCES.getString("files/htdocs/styles/OpenApiUI.css", null).orElse(null);
+               if (css == null)
+                       css = RESOURCES.getString("OpenApiUI.css", 
null).orElse(null);
+
+               var outer = div(
+                       style(css),
+                       script("text/javascript", 
RESOURCES.getString("OpenApiUI.js", null).orElse(null)),
+                       header(s)
+               )._class("openapi-ui");
+
+               // Operations without tags are rendered first.
+               outer.child(div()._class("tag-block 
tag-block-open").children(tagBlockContents(s, null)));
+
+               if (s.openApi.getTags() != null) {
+                       s.openApi.getTags().forEach(x -> {
+                               var tagBlock = div()._class("tag-block 
tag-block-open").children(
+                                       tagBlockSummary(x),
+                                       tagBlockContents(s, x)
+                               );
+                               outer.child(tagBlock);
+                       });
+               }
+
+               if (s.openApi.getComponents() != null && 
s.openApi.getComponents().getSchemas() != null) {
+                       var modelBlock = div()._class("tag-block").children(
+                               modelsBlockSummary(),
+                               modelsBlockContents(s)
+                       );
+                       outer.child(modelBlock);
+               }
+
+               return outer;
+       }
+
+       // Creates the informational summary before the ops.
+       private Table header(Session s) {
+               var table = table()._class("header");
+
+               var info = s.openApi.getInfo();
+               if (info != null) {
+
+                       if (info.getDescription() != null)
+                               
table.child(tr(th("Description:"),td(toBRL(info.getDescription()))));
+
+                       if (info.getVersion() != null)
+                               
table.child(tr(th("Version:"),td(info.getVersion())));
+
+                       var c = info.getContact();
+                       if (c != null) {
+                               var t2 = table();
+
+                               if (c.getName() != null)
+                                       
t2.child(tr(th("Name:"),td(c.getName())));
+                               if (c.getUrl() != null)
+                                       t2.child(tr(th("URL:"),td(a(c.getUrl(), 
c.getUrl()))));
+                               if (c.getEmail() != null)
+                                       
t2.child(tr(th("Email:"),td(a("mailto:"+ c.getEmail(), c.getEmail()))));
+
+                               table.child(tr(th("Contact:"),td(t2)));
+                       }
+
+                       var l = info.getLicense();
+                       if (l != null) {
+                               var content = l.getName() != null ? l.getName() 
: l.getUrl();
+                               var child = l.getUrl() != null ? a(l.getUrl(), 
content) : l.getName();
+                               table.child(tr(th("License:"),td(child)));
+                       }
+
+                       ExternalDocumentation ed = s.openApi.getExternalDocs();
+                       if (ed != null) {
+                               var content = ed.getDescription() != null ? 
ed.getDescription() : ed.getUrl();
+                               var child = ed.getUrl() != null ? 
a(ed.getUrl(), content) : ed.getDescription();
+                               table.child(tr(th("Docs:"),td(child)));
+                       }
+
+                       if (info.getTermsOfService() != null) {
+                               var tos = info.getTermsOfService();
+                               var child = StringUtils.isUri(tos) ? a(tos, 
tos) : tos;
+                               table.child(tr(th("Terms of 
Service:"),td(child)));
+                       }
+               }
+
+               return table;
+       }
+
+       // Creates the "pet  Everything about your Pets  ext-link" header.
+       private HtmlElement tagBlockSummary(Tag t) {
+               var ed = t.getExternalDocs();
+
+               var content = ed != null && ed.getDescription() != null ? 
ed.getDescription() : (ed != null ? ed.getUrl() : null);
+               return div()._class("tag-block-summary").children(
+                       span(t.getName())._class("name"),
+                       span(toBRL(t.getDescription()))._class("description"),
+                       ed != null && ed.getUrl() != null ? span(a(ed.getUrl(), 
content))._class("extdocs") : null
+               ).onclick("toggleTagBlock(this)");
+       }
+
+       // Creates the contents under the "pet  Everything about your Pets  
ext-link" header.
+       private Div tagBlockContents(Session s, Tag t) {
+               var tagBlockContents = div()._class("tag-block-contents");
+
+               if (s.openApi.getPaths() != null) {
+                       s.openApi.getPaths().forEach((path, pathItem) -> {
+                               // Check each HTTP method in the path item
+                               if (pathItem.getGet() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "get", pathItem.getGet(), 
t);
+                               if (pathItem.getPut() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "put", pathItem.getPut(), 
t);
+                               if (pathItem.getPost() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "post", pathItem.getPost(), 
t);
+                               if (pathItem.getDelete() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "delete", 
pathItem.getDelete(), t);
+                               if (pathItem.getOptions() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "options", 
pathItem.getOptions(), t);
+                               if (pathItem.getHead() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "head", pathItem.getHead(), 
t);
+                               if (pathItem.getPatch() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "patch", 
pathItem.getPatch(), t);
+                               if (pathItem.getTrace() != null)
+                                       
addOperationIfTagMatches(tagBlockContents, s, path, "trace", 
pathItem.getTrace(), t);
+                       });
+               }
+
+               return tagBlockContents;
+       }
+
+       private void addOperationIfTagMatches(Div tagBlockContents, Session s, 
String path, String method, Operation op, Tag t) {
+               if ((t == null && (op.getTags() == null || 
op.getTags().isEmpty())) || 
+                       (t != null && op.getTags() != null && 
op.getTags().contains(t.getName()))) {
+                       tagBlockContents.child(opBlock(s, path, method, op));
+               }
+       }
+
+       private Div opBlock(Session s, String path, String opName, Operation 
op) {
+
+               var opClass = op.getDeprecated() != null && op.getDeprecated() 
? "deprecated" : opName.toLowerCase();
+               if (!(op.getDeprecated() != null && op.getDeprecated()) && 
!STANDARD_METHODS.contains(opClass))
+                       opClass = "other";
+
+               return div()._class("op-block op-block-closed " + 
opClass).children(
+                       opBlockSummary(path, opName, op),
+                       div(tableContainer(s, op))._class("op-block-contents")
+               );
+       }
+
+       private HtmlElement opBlockSummary(String path, String opName, 
Operation op) {
+               return div()._class("op-block-summary").children(
+                       span(opName.toUpperCase())._class("method-button"),
+                       span(path)._class("path"),
+                       op.getSummary() != null ? 
span(op.getSummary())._class("summary") : null
+               ).onclick("toggleOpBlock(this)");
+       }
+
+       private Div tableContainer(Session s, Operation op) {
+               var tableContainer = div()._class("table-container");
+
+               if (op.getDescription() != null)
+                       
tableContainer.child(div(toBRL(op.getDescription()))._class("op-block-description"));
+
+               if (op.getParameters() != null) {
+                       
tableContainer.child(div(h4("Parameters")._class("title"))._class("op-block-section-header"));
+
+                       var parameters = 
table(tr(th("Name")._class("parameter-key"), 
th("Description")._class("parameter-key")))._class("parameters");
+
+                       op.getParameters().forEach(x -> {
+                               var piName = x.getName();
+                               var required = x.getRequired() != null && 
x.getRequired();
+
+                               var parameterKey = td(
+                                       div(piName)._class("name" + (required ? 
" required" : "")),
+                                       required ? 
div("required")._class("requiredlabel") : null,
+                                       x.getSchema() != null ? 
div(x.getSchema().getType())._class("type") : null,
+                                       div('(' + x.getIn() + ')')._class("in")
+                               )._class("parameter-key");
+
+                               var parameterValue = td(
+                                       
div(toBRL(x.getDescription()))._class("description"),
+                                       examples(s, x)
+                               )._class("parameter-value");
+
+                               parameters.child(tr(parameterKey, 
parameterValue));
+                       });
+
+                       tableContainer.child(parameters);
+               }
+
+               if (op.getResponses() != null) {
+                       
tableContainer.child(div(h4("Responses")._class("title"))._class("op-block-section-header"));
+
+                       var responses = 
table(tr(th("Code")._class("response-key"), 
th("Description")._class("response-key")))._class("responses");
+                       tableContainer.child(responses);
+
+                       op.getResponses().forEach((k,v) -> {
+                               var code = td(k)._class("response-key");
+
+                               var codeValue = td(
+                                       
div(toBRL(v.getDescription()))._class("description"),
+                                       examples(s, v),
+                                       headers(v)
+                               )._class("response-value");
+
+                               responses.child(tr(code, codeValue));
+                       });
+               }
+
+               return tableContainer;
+       }
+
+       private Div headers(Response ri) {
+               if (ri.getHeaders() == null)
+                       return null;
+
+               var sectionTable = 
table(tr(th("Name"),th("Description"),th("Schema")))._class("section-table");
+
+               var headers = div(
+                       div("Headers:")._class("section-name"),
+                       sectionTable
+               )._class("headers");
+
+               ri.getHeaders().forEach((k,v) ->
+                       sectionTable.child(
+                               tr(
+                                       td(k)._class("name"),
+                                       
td(toBRL(v.getDescription()))._class("description"),
+                                       
td(v.asMap().keepAll("type","format","items","collectionFormat","default","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","enum","multipleOf"))
+                               )
+                       )
+               );
+
+               return headers;
+       }
+
+       private Div examples(Session s, Parameter pi) {
+               var m = new JsonMap();
+
+               try {
+                       var si = pi.getSchema();
+                       if (si != null)
+                               m.put("model", si.copy().resolveRefs(s.openApi, 
new ArrayDeque<>(), s.resolveRefsMaxDepth));
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               if (m.isEmpty())
+                       return null;
+
+               return examplesDiv(m);
+       }
+
+       private Div examples(Session s, Response ri) {
+               var m = new JsonMap();
+               try {
+                       var content = ri.getContent();
+                       if (content != null) {
+                               // For OpenAPI 3.0, content is a map of media 
types to MediaType objects
+                               content.forEach((mediaType, mediaTypeObj) -> {
+                                       if (mediaTypeObj.getSchema() != null) {
+                                               try {
+                                                       var schema = 
mediaTypeObj.getSchema().copy().resolveRefs(s.openApi, new ArrayDeque<>(), 
s.resolveRefsMaxDepth);
+                                                       m.put(mediaType, 
schema);
+                                               } catch (Exception e) {
+                                                       e.printStackTrace();
+                                               }
+                                       }
+                               });
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               if (m.isEmpty())
+                       return null;
+
+               return examplesDiv(m);
+       }
+
+       private Div examplesDiv(JsonMap m) {
+               if (m.isEmpty())
+                       return null;
+
+               Select select = null;
+               if (m.size() > 1) {
+                       select = 
select().onchange("selectExample(this)")._class("example-select");
+               }
+
+               var div = div(select)._class("examples");
+
+               if (select != null)
+                       select.child(option("model","model"));
+               div.child(div(m.remove("model"))._class("model 
active").attr("data-name", "model"));
+
+               var select2 = select;
+               m.forEach((k,v) -> {
+                       if (select2 != null)
+                               select2.child(option(k, k));
+                       div.child(div(v.toString().replace("\\n", 
"\n"))._class("example").attr("data-name", k));
+               });
+
+               return div;
+       }
+
+       // Creates the "Model" header.
+       private HtmlElement modelsBlockSummary() {
+               return 
div()._class("tag-block-summary").children(span("Models")._class("name")).onclick("toggleTagBlock(this)");
+       }
+
+       // Creates the contents under the "Model" header.
+       private Div modelsBlockContents(Session s) {
+               var modelBlockContents = div()._class("tag-block-contents");
+               if (s.openApi.getComponents() != null && 
s.openApi.getComponents().getSchemas() != null) {
+                       s.openApi.getComponents().getSchemas().forEach((k,v) -> 
modelBlockContents.child(modelBlock(k,v)));
+               }
+               return modelBlockContents;
+       }
+
+       private Div modelBlock(String modelName, SchemaInfo model) {
+               return div()._class("op-block op-block-closed model").children(
+                       modelBlockSummary(modelName, model),
+                       div(model)._class("op-block-contents")
+               );
+       }
+
+       private HtmlElement modelBlockSummary(String modelName, SchemaInfo 
model) {
+               return div()._class("op-block-summary").children(
+                       span(modelName)._class("method-button"),
+                       model.getDescription() != null ? 
span(toBRL(model.getDescription()))._class("summary") : null
+               ).onclick("toggleOpBlock(this)");
+       }
+
+       /**
+        * Replaces newlines with <br> elements.
+        */
+       private static List<Object> toBRL(String s) {
+               if (s == null)
+                       return null;  // NOSONAR - Intentionally returning null.
+               if (s.indexOf(',') == -1)
+                       return singletonList(s);
+               var l = Utils.list();
+               var sa = s.split("\n");
+               for (var i = 0; i < sa.length; i++) {
+                       if (i > 0)
+                               l.add(br());
+                       l.add(sa[i]);
+               }
+               return l;
+       }
+}
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/package-info.java
similarity index 67%
copy from 
juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java
copy to 
juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/package-info.java
index 0d2ac4f34..2cb324eb7 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi/ui/package-info.java
@@ -10,29 +10,8 @@
 // * "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.dto.html5;
 
-import static org.apache.juneau.bean.html5.HtmlBuilder.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.bean.html5.*;
-import org.junit.jupiter.api.*;
-
-class Html5BasicTest extends SimpleTestBase {
-
-       @Test void a01_toString() {
-               Form f = form("bar",
-                       fieldset(
-                               legend("foo:"),
-                               "Name:", input("text"), br(),
-                               "Email:", input("text"), br(),
-                               "X:", keygen().name("X"),
-                               label("label")._for("Name")
-                       )
-               );
-
-               var r = f.toString();
-               assertEquals("<form 
action='bar'><fieldset><legend>foo:</legend>Name:<input 
type='text'/><br/>Email:<input type='text'/><br/>X:<keygen name='X'/><label 
for='Name'>label</label></fieldset></form>", r);
-       }
-}
\ No newline at end of file
+/**
+ * OpenAPI UI Generator
+ */
+package org.apache.juneau.bean.openapi.ui;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
old mode 100755
new mode 100644
similarity index 50%
copy from 
juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
copy to 
juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
index 416628883..d6031e8e6
--- 
a/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
@@ -10,35 +10,74 @@
 // * "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.a.rttests;
+package org.apache.juneau.bean.openapi3;
 
-import static org.apache.juneau.TestUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
 
-import org.apache.juneau.bean.jsonschema.*;
-import org.apache.juneau.dto.jsonschema.*;
-import org.junit.jupiter.params.*;
-import org.junit.jupiter.params.provider.*;
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
 
 /**
- * Tests designed to serialize and parse objects to make sure we end up
- * with the same objects for all serializers and parsers.
+ * A map of possible out-of-band callbacks related to the parent operation.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
  */
-class DTOs_RoundTripTest extends RoundTripTest_Base {
-
-       @ParameterizedTest
-       @MethodSource("testers")
-       void a01_jsonSchema1(RoundTrip_Tester t) throws Exception {
-               var x1 = JsonSchema_Test.getTest1();
-               var x2 = t.roundTrip(x1, JsonSchema.class);
-               assertEquals(json(x2), json(x1));
+@Bean(properties="*")
+@FluentSetters
+public class Callback extends OpenApiElement {
+
+       private Map<String,PathItem> callbacks;
+
+       /**
+        * Default constructor.
+        */
+       public Callback() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public Callback(Callback copyFrom) {
+               super(copyFrom);
+               this.callbacks = copyOf(copyFrom.callbacks);
+       }
+
+       /**
+        * Returns the callbacks map.
+        *
+        * @return The callbacks map.
+        */
+       public Map<String,PathItem> getCallbacks() {
+               return callbacks;
+       }
+
+       /**
+        * Sets the callbacks map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Callback setCallbacks(Map<String,PathItem> value) {
+               this.callbacks = value;
+               return this;
        }
 
-       @ParameterizedTest
-       @MethodSource("testers")
-       void a02_jsonSchema2(RoundTrip_Tester t) throws Exception {
-               var x1 = JsonSchema_Test.getTest2();
-               var x2 = t.roundTrip(x1, JsonSchema.class);
-               assertEquals(json(x2), json(x1));
+       /**
+        * Adds a callback.
+        *
+        * @param expression The callback expression.
+        * @param pathItem The path item for the callback.
+        * @return This object.
+        */
+       public Callback addCallback(String expression, PathItem pathItem) {
+               if (callbacks == null)
+                       callbacks = new LinkedHashMap<>();
+               callbacks.put(expression, pathItem);
+               return this;
        }
-}
\ No newline at end of file
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
new file mode 100644
index 000000000..2e762647f
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
@@ -0,0 +1,245 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Holds a set of reusable objects for different aspects of the OAS.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="schemas,responses,parameters,examples,requestBodies,headers,securitySchemes,links,callbacks,*")
+@FluentSetters
+public class Components extends OpenApiElement {
+
+       private Map<String,SchemaInfo> schemas;
+       private Map<String,Response> responses;
+       private Map<String,Parameter> parameters;
+       private Map<String,Example> examples;
+       private Map<String,RequestBodyInfo> requestBodies;
+       private Map<String,HeaderInfo> headers;
+       private Map<String,SecuritySchemeInfo> securitySchemes;
+       private Map<String,Link> links;
+       private Map<String,Callback> callbacks;
+
+       /**
+        * Default constructor.
+        */
+       public Components() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public Components(Components copyFrom) {
+               super(copyFrom);
+               this.schemas = copyOf(copyFrom.schemas);
+               this.responses = copyOf(copyFrom.responses);
+               this.parameters = copyOf(copyFrom.parameters);
+               this.examples = copyOf(copyFrom.examples);
+               this.requestBodies = copyOf(copyFrom.requestBodies);
+               this.headers = copyOf(copyFrom.headers);
+               this.securitySchemes = copyOf(copyFrom.securitySchemes);
+               this.links = copyOf(copyFrom.links);
+               this.callbacks = copyOf(copyFrom.callbacks);
+       }
+
+       /**
+        * Returns the schemas map.
+        *
+        * @return The schemas map.
+        */
+       public Map<String,SchemaInfo> getSchemas() {
+               return schemas;
+       }
+
+       /**
+        * Sets the schemas map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setSchemas(Map<String,SchemaInfo> value) {
+               this.schemas = value;
+               return this;
+       }
+
+       /**
+        * Returns the responses map.
+        *
+        * @return The responses map.
+        */
+       public Map<String,Response> getResponses() {
+               return responses;
+       }
+
+       /**
+        * Sets the responses map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setResponses(Map<String,Response> value) {
+               this.responses = value;
+               return this;
+       }
+
+       /**
+        * Returns the parameters map.
+        *
+        * @return The parameters map.
+        */
+       public Map<String,Parameter> getParameters() {
+               return parameters;
+       }
+
+       /**
+        * Sets the parameters map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setParameters(Map<String,Parameter> value) {
+               this.parameters = value;
+               return this;
+       }
+
+       /**
+        * Returns the examples map.
+        *
+        * @return The examples map.
+        */
+       public Map<String,Example> getExamples() {
+               return examples;
+       }
+
+       /**
+        * Sets the examples map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setExamples(Map<String,Example> value) {
+               this.examples = value;
+               return this;
+       }
+
+       /**
+        * Returns the request bodies map.
+        *
+        * @return The request bodies map.
+        */
+       public Map<String,RequestBodyInfo> getRequestBodies() {
+               return requestBodies;
+       }
+
+       /**
+        * Sets the request bodies map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setRequestBodies(Map<String,RequestBodyInfo> value) {
+               this.requestBodies = value;
+               return this;
+       }
+
+       /**
+        * Returns the headers map.
+        *
+        * @return The headers map.
+        */
+       public Map<String,HeaderInfo> getHeaders() {
+               return headers;
+       }
+
+       /**
+        * Sets the headers map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setHeaders(Map<String,HeaderInfo> value) {
+               this.headers = value;
+               return this;
+       }
+
+       /**
+        * Returns the security schemes map.
+        *
+        * @return The security schemes map.
+        */
+       public Map<String,SecuritySchemeInfo> getSecuritySchemes() {
+               return securitySchemes;
+       }
+
+       /**
+        * Sets the security schemes map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setSecuritySchemes(Map<String,SecuritySchemeInfo> 
value) {
+               this.securitySchemes = value;
+               return this;
+       }
+
+       /**
+        * Returns the links map.
+        *
+        * @return The links map.
+        */
+       public Map<String,Link> getLinks() {
+               return links;
+       }
+
+       /**
+        * Sets the links map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setLinks(Map<String,Link> value) {
+               this.links = value;
+               return this;
+       }
+
+       /**
+        * Returns the callbacks map.
+        *
+        * @return The callbacks map.
+        */
+       public Map<String,Callback> getCallbacks() {
+               return callbacks;
+       }
+
+       /**
+        * Sets the callbacks map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Components setCallbacks(Map<String,Callback> value) {
+               this.callbacks = value;
+               return this;
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
index 0c57e985c..cede8cdfa 100644
--- 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
@@ -18,7 +18,6 @@ import static org.apache.juneau.internal.ConverterUtils.*;
 import java.util.*;
 
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.internal.*;
 
@@ -449,7 +448,7 @@ public class HeaderInfo extends OpenApiElement {
        /**
         * Resolves any <js>"$ref"</js> attributes in this element.
         *
-        * @param swagger The swagger document containing the definitions.
+        * @param openApi The swagger document containing the definitions.
         * @param refStack Keeps track of previously-visited references so that 
we don't cause recursive loops.
         * @param maxDepth
         *      The maximum depth to resolve references.
@@ -459,13 +458,14 @@ public class HeaderInfo extends OpenApiElement {
         *      This object with references resolved.
         *      <br>May or may not be the same object.
         */
-       public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack, 
int maxDepth) {
+       public HeaderInfo resolveRefs(OpenApi openApi, Deque<String> refStack, 
int maxDepth) {
 
                if (ref != null) {
                        if (refStack.contains(ref) || refStack.size() >= 
maxDepth)
                                return this;
                        refStack.addLast(ref);
-                       var r = swagger.findRef(ref, 
HeaderInfo.class).resolveRefs(swagger, refStack, maxDepth);
+                       var r = openApi.findRef(ref, HeaderInfo.class);
+                       r = r.resolveRefs(openApi, refStack, maxDepth);
                        refStack.removeLast();
                        return r;
                }
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
index be5fc1c84..a1b33a0c2 100644
--- 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
@@ -21,7 +21,6 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.internal.*;
@@ -745,7 +744,7 @@ public class Items extends OpenApiElement {
        /**
         * Resolves any <js>"$ref"</js> attributes in this element.
         *
-        * @param swagger The swagger document containing the definitions.
+        * @param openApi The swagger document containing the definitions.
         * @param refStack Keeps track of previously-visited references so that 
we don't cause recursive loops.
         * @param maxDepth
         *      The maximum depth to resolve references.
@@ -755,21 +754,22 @@ public class Items extends OpenApiElement {
         *      This object with references resolved.
         *      <br>May or may not be the same object.
         */
-       public Items resolveRefs(Swagger swagger, Deque<String> refStack, int 
maxDepth) {
+       public Items resolveRefs(OpenApi openApi, Deque<String> refStack, int 
maxDepth) {
 
                if (ref != null) {
                        if (refStack.contains(ref) || refStack.size() >= 
maxDepth)
                                return this;
                        refStack.addLast(ref);
-                       var r = swagger.findRef(ref, 
Items.class).resolveRefs(swagger, refStack, maxDepth);
+                       var r = openApi.findRef(ref, Items.class);
+                       r = r.resolveRefs(openApi, refStack, maxDepth);
                        refStack.removeLast();
                        return r;
                }
 
-               set("properties", resolveRefs(get("properties"), swagger, 
refStack, maxDepth));
+               set("properties", resolveRefs(get("properties"), openApi, 
refStack, maxDepth));
 
                if (items != null)
-                       items = items.resolveRefs(swagger, refStack, maxDepth);
+                       items = items.resolveRefs(openApi, refStack, maxDepth);
 
                set("example", null);
 
@@ -777,7 +777,7 @@ public class Items extends OpenApiElement {
        }
 
        /* Resolve references in extra attributes */
-       private Object resolveRefs(Object o, Swagger swagger, Deque<String> 
refStack, int maxDepth) {
+       private Object resolveRefs(Object o, OpenApi openApi, Deque<String> 
refStack, int maxDepth) {
                if (o instanceof JsonMap om) {
                        var ref2 = om.get("$ref");
                        if (ref2 instanceof CharSequence) {
@@ -785,17 +785,17 @@ public class Items extends OpenApiElement {
                                if (refStack.contains(sref) || refStack.size() 
>= maxDepth)
                                        return o;
                                refStack.addLast(sref);
-                               var o2 = swagger.findRef(sref, Object.class);
-                               o2 = resolveRefs(o2, swagger, refStack, 
maxDepth);
+                               var o2 = openApi.findRef(sref, Object.class);
+                               o2 = resolveRefs(o2, openApi, refStack, 
maxDepth);
                                refStack.removeLast();
                                return o2;
                        }
                        for (var e : om.entrySet())
-                               e.setValue(resolveRefs(e.getValue(), swagger, 
refStack, maxDepth));
+                               e.setValue(resolveRefs(e.getValue(), openApi, 
refStack, maxDepth));
                }
                if (o instanceof JsonList x)
                        for (var li = x.listIterator(); li.hasNext();)
-                               li.set(resolveRefs(li.next(), swagger, 
refStack, maxDepth));
+                               li.set(resolveRefs(li.next(), openApi, 
refStack, maxDepth));
                return o;
        }
 }
\ No newline at end of file
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
new file mode 100644
index 000000000..628816d98
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
@@ -0,0 +1,281 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+import java.util.TreeMap;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.common.internal.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.objecttools.*;
+
+/**
+ * This is the root document object for the OpenAPI specification.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="openapi,info,servers,paths,components,security,tags,externalDocs,*")
+@FluentSetters
+public class OpenApi extends OpenApiElement {
+
+       /** Represents a null OpenAPI document */
+       public static final OpenApi NULL = new OpenApi();
+
+       private static final Comparator<String> PATH_COMPARATOR = (o1, o2) -> 
o1.replace('{', '@').compareTo(o2.replace('{', '@'));
+
+       private String openapi = "3.0.0";
+       private Info info;
+       private List<Server> servers;
+       private Map<String,PathItem> paths;
+       private Components components;
+       private List<SecurityRequirement> security;
+       private List<Tag> tags;
+       private ExternalDocumentation externalDocs;
+
+       /**
+        * Default constructor.
+        */
+       public OpenApi() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public OpenApi(OpenApi copyFrom) {
+               super(copyFrom);
+               this.openapi = copyFrom.openapi;
+               this.info = copyFrom.info;
+               this.servers = copyOf(copyFrom.servers);
+               this.paths = copyOf(copyFrom.paths);
+               this.components = copyFrom.components;
+               this.security = copyOf(copyFrom.security);
+               this.tags = copyOf(copyFrom.tags);
+               this.externalDocs = copyFrom.externalDocs;
+       }
+
+       /**
+        * Make a deep copy of this object.
+        *
+        * @return A deep copy of this object.
+        */
+       public OpenApi copy() {
+               return new OpenApi(this);
+       }
+
+       /**
+        * Returns the OpenAPI version.
+        *
+        * @return The OpenAPI version.
+        */
+       public String getOpenapi() {
+               return openapi;
+       }
+
+       /**
+        * Sets the OpenAPI version.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setOpenapi(String value) {
+               this.openapi = value;
+               return this;
+       }
+
+       /**
+        * Returns the info object.
+        *
+        * @return The info object.
+        */
+       public Info getInfo() {
+               return info;
+       }
+
+       /**
+        * Sets the info object.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setInfo(Info value) {
+               this.info = value;
+               return this;
+       }
+
+       /**
+        * Returns the servers list.
+        *
+        * @return The servers list.
+        */
+       public List<Server> getServers() {
+               return servers;
+       }
+
+       /**
+        * Sets the servers list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setServers(List<Server> value) {
+               this.servers = value;
+               return this;
+       }
+
+       /**
+        * Returns the paths map.
+        *
+        * @return The paths map.
+        */
+       public Map<String,PathItem> getPaths() {
+               return paths;
+       }
+
+       /**
+        * Sets the paths map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setPaths(Map<String,PathItem> value) {
+               this.paths = 
mapBuilder(String.class,PathItem.class).sparse().sorted(PATH_COMPARATOR).addAll(value).build();
+               return this;
+       }
+
+       /**
+        * Adds a path to this OpenAPI document.
+        *
+        * @param path The path string.
+        * @param pathItem The path item.
+        * @return This object.
+        */
+       public OpenApi addPath(String path, PathItem pathItem) {
+               if (paths == null)
+                       paths = new TreeMap<>(PATH_COMPARATOR);
+               getPaths().put(path, pathItem);
+               return this;
+       }
+
+       /**
+        * Returns the components object.
+        *
+        * @return The components object.
+        */
+       public Components getComponents() {
+               return components;
+       }
+
+       /**
+        * Sets the components object.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setComponents(Components value) {
+               this.components = value;
+               return this;
+       }
+
+       /**
+        * Returns the security requirements list.
+        *
+        * @return The security requirements list.
+        */
+       public List<SecurityRequirement> getSecurity() {
+               return security;
+       }
+
+       /**
+        * Sets the security requirements list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setSecurity(List<SecurityRequirement> value) {
+               this.security = value;
+               return this;
+       }
+
+       /**
+        * Returns the tags list.
+        *
+        * @return The tags list.
+        */
+       public List<Tag> getTags() {
+               return tags;
+       }
+
+       /**
+        * Sets the tags list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setTags(List<Tag> value) {
+               this.tags = value;
+               return this;
+       }
+
+       /**
+        * Returns the external documentation.
+        *
+        * @return The external documentation.
+        */
+       public ExternalDocumentation getExternalDocs() {
+               return externalDocs;
+       }
+
+       /**
+        * Sets the external documentation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public OpenApi setExternalDocs(ExternalDocumentation value) {
+               this.externalDocs = value;
+               return this;
+       }
+
+       /**
+        * Finds a reference within this OpenAPI document.
+        *
+        * @param ref The reference string (e.g., 
<js>"#/components/schemas/User"</js>).
+        * @param c The expected class type.
+        * @return The referenced node, or <jk>null</jk> if the ref was 
<jk>null</jk> or empty or not found.
+        */
+       public <T> T findRef(String ref, Class<T> c) {
+               if (Utils.isEmpty(ref))
+                       return null;
+               if (! ref.startsWith("#/"))
+                       throw new BasicRuntimeException("Unsupported reference: 
 ''{0}''", ref);
+               try {
+                       return new ObjectRest(this).get(ref.substring(1), c);
+               } catch (Exception e) {
+                       throw new BeanRuntimeException(e, c, "Reference ''{0}'' 
could not be converted to type ''{1}''.", ref, className(c));
+               }
+       }
+
+       @Override
+       public String toString() {
+               return JsonSerializer.DEFAULT_READABLE.toString(this);
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiBuilder.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiBuilder.java
new file mode 100644
index 000000000..3b5c0da44
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiBuilder.java
@@ -0,0 +1,302 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import java.net.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.common.internal.*;
+
+/**
+ * Various useful static methods for creating OpenAPI elements.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+public class OpenApiBuilder {
+
+       /**
+        * Constructor.
+        */
+       protected OpenApiBuilder() {}
+
+       /**
+        * Creates an empty {@link Contact} element.
+        *
+        * @return The new element.
+        */
+       public static final Contact contact() {
+               return new Contact();
+       }
+
+       /**
+        * Creates an {@link Contact} element with the specified {@link 
Contact#setName(String) name} attribute.
+        *
+        * @param name The {@link Contact#setName(String) name} attribute.
+        * @return The new element.
+        */
+       public static final Contact contact(String name) {
+               return contact().setName(name);
+       }
+
+       /**
+        * Creates an {@link Contact} element with the specified {@link 
Contact#setName(String) name}, {@link Contact#setUrl(URI) url},
+        * and {@link Contact#setEmail(String) email} attributes.
+        *
+        * @param name The {@link Contact#setName(String) name} attribute.
+        * @param url
+        *      The {@link Contact#setUrl(URI) url} attribute.
+        *      <br>The value can be of any of the following types: {@link 
URI}, {@link URL}, {@link String}.
+        *      <br>Strings must be valid URIs.
+        *      <br>URIs defined by {@link UriResolver} can be used for values.
+        * @param email The {@link Contact#setEmail(String) email} attribute.
+        * @return The new element.
+        */
+       public static final Contact contact(String name, Object url, String 
email) {
+               return 
contact().setName(name).setUrl(StringUtils.toURI(url)).setEmail(email);
+       }
+
+       /**
+        * Creates an empty {@link ExternalDocumentation} element.
+        *
+        * @return The new element.
+        */
+       public static final ExternalDocumentation externalDocumentation() {
+               return new ExternalDocumentation();
+       }
+
+       /**
+        * Creates an {@link ExternalDocumentation} element with the specified 
{@link ExternalDocumentation#setUrl(URI) url}
+        * attribute.
+        *
+        * @param url
+        *      The {@link ExternalDocumentation#setUrl(URI) url} attribute.
+        *      <br>The value can be of any of the following types: {@link 
URI}, {@link URL}, {@link String}.
+        *      <br>Strings must be valid URIs.
+        *      <br>URIs defined by {@link UriResolver} can be used for values.
+        * @return The new element.
+        */
+       public static final ExternalDocumentation externalDocumentation(Object 
url) {
+               return externalDocumentation().setUrl(StringUtils.toURI(url));
+       }
+
+       /**
+        * Creates an {@link ExternalDocumentation} element with the specified 
{@link ExternalDocumentation#setUrl(URI) url}
+        * and {@link ExternalDocumentation#setDescription(String) description} 
attributes.
+        *
+        * @param url
+        *      The {@link ExternalDocumentation#setUrl(URI) url} attribute.
+        *      <br>The value can be of any of the following types: {@link 
URI}, {@link URL}, {@link String}.
+        *      <br>Strings must be valid URIs.
+        *      <br>URIs defined by {@link UriResolver} can be used for values.
+        * @param description The {@link 
ExternalDocumentation#setDescription(String) description} attribute.
+        * @return The new element.
+        */
+       public static final ExternalDocumentation externalDocumentation(Object 
url, String description) {
+               return 
externalDocumentation().setUrl(StringUtils.toURI(url)).setDescription(description);
+       }
+
+       /**
+        * Creates an empty {@link HeaderInfo} element.
+        *
+        * @return The new element.
+        */
+       public static final HeaderInfo headerInfo() {
+               return new HeaderInfo();
+       }
+
+       /**
+        * Creates an {@link HeaderInfo} element with the specified {@link 
HeaderInfo#setSchema(SchemaInfo) schema} attribute.
+        *
+        * @param schema The {@link HeaderInfo#setSchema(SchemaInfo) schema} 
attribute.
+        * @return The new element.
+        */
+       public static final HeaderInfo headerInfo(SchemaInfo schema) {
+               return headerInfo().setSchema(schema);
+       }
+
+       /**
+        * Creates an empty {@link Info} element.
+        *
+        * @return The new element.
+        */
+       public static final Info info() {
+               return new Info();
+       }
+
+       /**
+        * Creates an {@link Info} element with the specified {@link 
Info#setTitle(String) title} and {@link Info#setVersion(String) version}
+        * attributes.
+        *
+        * @param title The {@link Info#setTitle(String) title} attribute.
+        * @param version The {@link Info#setVersion(String) version} attribute.
+        * @return The new element.
+        */
+       public static final Info info(String title, String version) {
+               return info().setTitle(title).setVersion(version);
+       }
+
+       /**
+        * Creates an empty {@link Items} element.
+        *
+        * @return The new element.
+        */
+       public static final Items items() {
+               return new Items();
+       }
+
+       /**
+        * Creates an {@link Items} element with the specified {@link 
Items#setType(String) type} attribute.
+        *
+        * @param type The {@link Items#setType(String) type} attribute.
+        * @return The new element.
+        */
+       public static final Items items(String type) {
+               return items().setType(type);
+       }
+
+       /**
+        * Creates an empty {@link License} element.
+        *
+        * @return The new element.
+        */
+       public static final License license() {
+               return new License();
+       }
+
+       /**
+        * Creates an {@link License} element with the specified {@link 
License#setName(String) name} attribute.
+        *
+        * @param name The {@link License#setName(String) name} attribute.
+        * @return The new element.
+        */
+       public static final License license(String name) {
+               return license().setName(name);
+       }
+
+       /**
+        * Creates an {@link License} element with the specified {@link 
License#setName(String) name} and {@link License#setUrl(URI) url} attributes.
+        *
+        * @param name The {@link License#setName(String) name} attribute.
+        * @param url The {@link License#setUrl(URI) url} attribute.
+        * @return The new element.
+        */
+       public static final License license(String name, URI url) {
+               return license().setName(name).setUrl(url);
+       }
+
+       /**
+        * Creates an empty {@link OpenApi} element.
+        *
+        * @return The new element.
+        */
+       public static final OpenApi openApi() {
+               return new OpenApi();
+       }
+
+       /**
+        * Creates an {@link OpenApi} element with the specified {@link 
OpenApi#setInfo(Info) info} attribute.
+        *
+        * @param info The {@link OpenApi#setInfo(Info) info} attribute.
+        * @return The new element.
+        */
+       public static final OpenApi openApi(Info info) {
+               return openApi().setInfo(info);
+       }
+
+       /**
+        * Creates an empty {@link SchemaInfo} element.
+        *
+        * @return The new element.
+        */
+       public static final SchemaInfo schemaInfo() {
+               return new SchemaInfo();
+       }
+
+       /**
+        * Creates an {@link SchemaInfo} element with the specified {@link 
SchemaInfo#setType(String) type} attribute.
+        *
+        * @param type The {@link SchemaInfo#setType(String) type} attribute.
+        * @return The new element.
+        */
+       public static final SchemaInfo schemaInfo(String type) {
+               return schemaInfo().setType(type);
+       }
+
+       /**
+        * Creates an empty {@link SecuritySchemeInfo} element.
+        *
+        * @return The new element.
+        */
+       public static final SecuritySchemeInfo securitySchemeInfo() {
+               return new SecuritySchemeInfo();
+       }
+
+       /**
+        * Creates an {@link SecuritySchemeInfo} element with the specified 
{@link SecuritySchemeInfo#setType(String) type} attribute.
+        *
+        * @param type The {@link SecuritySchemeInfo#setType(String) type} 
attribute.
+        * @return The new element.
+        */
+       public static final SecuritySchemeInfo securitySchemeInfo(String type) {
+               return securitySchemeInfo().setType(type);
+       }
+
+       /**
+        * Creates an empty {@link Server} element.
+        *
+        * @return The new element.
+        */
+       public static final Server server() {
+               return new Server();
+       }
+
+       /**
+        * Creates an {@link Server} element with the specified {@link 
Server#setUrl(URI) url} attribute.
+        *
+        * @param url The {@link Server#setUrl(URI) url} attribute.
+        * @return The new element.
+        */
+       public static final Server server(URI url) {
+               return server().setUrl(url);
+       }
+
+       /**
+        * Creates an empty {@link Tag} element.
+        *
+        * @return The new element.
+        */
+       public static final Tag tag() {
+               return new Tag();
+       }
+
+       /**
+        * Creates an {@link Tag} element with the specified {@link 
Tag#setName(String) name} attribute.
+        *
+        * @param name The {@link Tag#setName(String) name} attribute.
+        * @return The new element.
+        */
+       public static final Tag tag(String name) {
+               return tag().setName(name);
+       }
+
+       /**
+        * Creates an empty {@link Xml} element.
+        *
+        * @return The new element.
+        */
+       public static final Xml xml() {
+               return new Xml();
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
new file mode 100644
index 000000000..35db3279c
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
@@ -0,0 +1,309 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Describes a single API operation on a path.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="tags,summary,description,externalDocs,operationId,parameters,requestBody,responses,callbacks,deprecated,security,servers,*")
+@FluentSetters
+public class Operation extends OpenApiElement {
+
+       private List<String> tags;
+       private String summary, description, operationId;
+       private ExternalDocumentation externalDocs;
+       private List<Parameter> parameters;
+       private RequestBodyInfo requestBody;
+       private Map<String,Response> responses;
+       private Map<String,Callback> callbacks;
+       private Boolean deprecated;
+       private List<SecurityRequirement> security;
+       private List<Server> servers;
+
+       /**
+        * Default constructor.
+        */
+       public Operation() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public Operation(Operation copyFrom) {
+               super(copyFrom);
+               this.tags = copyOf(copyFrom.tags);
+               this.summary = copyFrom.summary;
+               this.description = copyFrom.description;
+               this.operationId = copyFrom.operationId;
+               this.externalDocs = copyFrom.externalDocs;
+               this.parameters = copyOf(copyFrom.parameters);
+               this.requestBody = copyFrom.requestBody;
+               this.responses = copyOf(copyFrom.responses);
+               this.callbacks = copyOf(copyFrom.callbacks);
+               this.deprecated = copyFrom.deprecated;
+               this.security = copyOf(copyFrom.security);
+               this.servers = copyOf(copyFrom.servers);
+       }
+
+       /**
+        * Returns the tags list.
+        *
+        * @return The tags list.
+        */
+       public List<String> getTags() {
+               return tags;
+       }
+
+       /**
+        * Sets the tags list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setTags(List<String> value) {
+               this.tags = value;
+               return this;
+       }
+
+       /**
+        * Returns the summary.
+        *
+        * @return The summary.
+        */
+       public String getSummary() {
+               return summary;
+       }
+
+       /**
+        * Sets the summary.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setSummary(String value) {
+               this.summary = value;
+               return this;
+       }
+
+       /**
+        * Returns the description.
+        *
+        * @return The description.
+        */
+       public String getDescription() {
+               return description;
+       }
+
+       /**
+        * Sets the description.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setDescription(String value) {
+               this.description = value;
+               return this;
+       }
+
+       /**
+        * Returns the operation ID.
+        *
+        * @return The operation ID.
+        */
+       public String getOperationId() {
+               return operationId;
+       }
+
+       /**
+        * Sets the operation ID.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setOperationId(String value) {
+               this.operationId = value;
+               return this;
+       }
+
+       /**
+        * Returns the external documentation.
+        *
+        * @return The external documentation.
+        */
+       public ExternalDocumentation getExternalDocs() {
+               return externalDocs;
+       }
+
+       /**
+        * Sets the external documentation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setExternalDocs(ExternalDocumentation value) {
+               this.externalDocs = value;
+               return this;
+       }
+
+       /**
+        * Returns the parameters list.
+        *
+        * @return The parameters list.
+        */
+       public List<Parameter> getParameters() {
+               return parameters;
+       }
+
+       /**
+        * Sets the parameters list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setParameters(List<Parameter> value) {
+               this.parameters = value;
+               return this;
+       }
+
+       /**
+        * Returns the request body.
+        *
+        * @return The request body.
+        */
+       public RequestBodyInfo getRequestBody() {
+               return requestBody;
+       }
+
+       /**
+        * Sets the request body.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setRequestBody(RequestBodyInfo value) {
+               this.requestBody = value;
+               return this;
+       }
+
+       /**
+        * Returns the responses map.
+        *
+        * @return The responses map.
+        */
+       public Map<String,Response> getResponses() {
+               return responses;
+       }
+
+       /**
+        * Sets the responses map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setResponses(Map<String,Response> value) {
+               this.responses = value;
+               return this;
+       }
+
+       /**
+        * Returns the callbacks map.
+        *
+        * @return The callbacks map.
+        */
+       public Map<String,Callback> getCallbacks() {
+               return callbacks;
+       }
+
+       /**
+        * Sets the callbacks map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setCallbacks(Map<String,Callback> value) {
+               this.callbacks = value;
+               return this;
+       }
+
+       /**
+        * Returns the deprecated flag.
+        *
+        * @return The deprecated flag.
+        */
+       public Boolean getDeprecated() {
+               return deprecated;
+       }
+
+       /**
+        * Sets the deprecated flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setDeprecated(Boolean value) {
+               this.deprecated = value;
+               return this;
+       }
+
+       /**
+        * Returns the security requirements list.
+        *
+        * @return The security requirements list.
+        */
+       public List<SecurityRequirement> getSecurity() {
+               return security;
+       }
+
+       /**
+        * Sets the security requirements list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setSecurity(List<SecurityRequirement> value) {
+               this.security = value;
+               return this;
+       }
+
+       /**
+        * Returns the servers list.
+        *
+        * @return The servers list.
+        */
+       public List<Server> getServers() {
+               return servers;
+       }
+
+       /**
+        * Sets the servers list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Operation setServers(List<Server> value) {
+               this.servers = value;
+               return this;
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
new file mode 100644
index 000000000..f1316c7a8
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
@@ -0,0 +1,320 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.common.internal.Utils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.marshaller.*;
+
+/**
+ * Describes a single operation parameter.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="name,in,description,required,deprecated,allowEmptyValue,style,explode,allowReserved,schema,example,examples,*")
+@FluentSetters
+public class Parameter extends OpenApiElement {
+
+       private static final String[] VALID_IN = {"query", "header", "path", 
"cookie"};
+       private static final String[] VALID_STYLES = {"matrix", "label", 
"form", "simple", "spaceDelimited", "pipeDelimited", "deepObject"};
+
+       private String name, in, description, style;
+       private Boolean required, deprecated, allowEmptyValue, explode, 
allowReserved;
+       private SchemaInfo schema;
+       private Object example;
+       private Map<String,Example> examples;
+
+       /**
+        * Default constructor.
+        */
+       public Parameter() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public Parameter(Parameter copyFrom) {
+               super(copyFrom);
+               this.name = copyFrom.name;
+               this.in = copyFrom.in;
+               this.description = copyFrom.description;
+               this.style = copyFrom.style;
+               this.required = copyFrom.required;
+               this.deprecated = copyFrom.deprecated;
+               this.allowEmptyValue = copyFrom.allowEmptyValue;
+               this.explode = copyFrom.explode;
+               this.allowReserved = copyFrom.allowReserved;
+               this.schema = copyFrom.schema;
+               this.example = copyFrom.example;
+               this.examples = copyOf(copyFrom.examples);
+       }
+
+       /**
+        * Returns the parameter name.
+        *
+        * @return The parameter name.
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Sets the parameter name.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setName(String value) {
+               this.name = value;
+               return this;
+       }
+
+       /**
+        * Returns the parameter location.
+        *
+        * @return The parameter location.
+        */
+       public String getIn() {
+               return in;
+       }
+
+       /**
+        * Sets the parameter location.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setIn(String value) {
+               if (isStrict() && ! contains(value, VALID_IN))
+                       throw new BasicRuntimeException(
+                               "Invalid value passed in to setIn(String).  
Value=''{0}'', valid values={1}",
+                               value, Json5.of(VALID_IN)
+                       );
+               this.in = value;
+               return this;
+       }
+
+       /**
+        * Returns the description.
+        *
+        * @return The description.
+        */
+       public String getDescription() {
+               return description;
+       }
+
+       /**
+        * Sets the description.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setDescription(String value) {
+               this.description = value;
+               return this;
+       }
+
+       /**
+        * Returns the style.
+        *
+        * @return The style.
+        */
+       public String getStyle() {
+               return style;
+       }
+
+       /**
+        * Sets the style.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setStyle(String value) {
+               if (isStrict() && ! contains(value, VALID_STYLES))
+                       throw new BasicRuntimeException(
+                               "Invalid value passed in to setStyle(String).  
Value=''{0}'', valid values={1}",
+                               value, Json5.of(VALID_STYLES)
+                       );
+               this.style = value;
+               return this;
+       }
+
+       /**
+        * Returns the required flag.
+        *
+        * @return The required flag.
+        */
+       public Boolean getRequired() {
+               return required;
+       }
+
+       /**
+        * Sets the required flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setRequired(Boolean value) {
+               this.required = value;
+               return this;
+       }
+
+       /**
+        * Returns the deprecated flag.
+        *
+        * @return The deprecated flag.
+        */
+       public Boolean getDeprecated() {
+               return deprecated;
+       }
+
+       /**
+        * Sets the deprecated flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setDeprecated(Boolean value) {
+               this.deprecated = value;
+               return this;
+       }
+
+       /**
+        * Returns the allow empty value flag.
+        *
+        * @return The allow empty value flag.
+        */
+       public Boolean getAllowEmptyValue() {
+               return allowEmptyValue;
+       }
+
+       /**
+        * Sets the allow empty value flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setAllowEmptyValue(Boolean value) {
+               this.allowEmptyValue = value;
+               return this;
+       }
+
+       /**
+        * Returns the explode flag.
+        *
+        * @return The explode flag.
+        */
+       public Boolean getExplode() {
+               return explode;
+       }
+
+       /**
+        * Sets the explode flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setExplode(Boolean value) {
+               this.explode = value;
+               return this;
+       }
+
+       /**
+        * Returns the allow reserved flag.
+        *
+        * @return The allow reserved flag.
+        */
+       public Boolean getAllowReserved() {
+               return allowReserved;
+       }
+
+       /**
+        * Sets the allow reserved flag.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setAllowReserved(Boolean value) {
+               this.allowReserved = value;
+               return this;
+       }
+
+       /**
+        * Returns the schema.
+        *
+        * @return The schema.
+        */
+       public SchemaInfo getSchema() {
+               return schema;
+       }
+
+       /**
+        * Sets the schema.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setSchema(SchemaInfo value) {
+               this.schema = value;
+               return this;
+       }
+
+       /**
+        * Returns the example.
+        *
+        * @return The example.
+        */
+       public Object getExample() {
+               return example;
+       }
+
+       /**
+        * Sets the example.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setExample(Object value) {
+               this.example = value;
+               return this;
+       }
+
+       /**
+        * Returns the examples map.
+        *
+        * @return The examples map.
+        */
+       public Map<String,Example> getExamples() {
+               return examples;
+       }
+
+       /**
+        * Sets the examples map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public Parameter setExamples(Map<String,Example> value) {
+               this.examples = value;
+               return this;
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
new file mode 100644
index 000000000..15dcd6fe2
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
@@ -0,0 +1,303 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Describes the operations available on a single path.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="summary,description,get,put,post,delete,options,head,patch,trace,servers,parameters,*")
+@FluentSetters
+public class PathItem extends OpenApiElement {
+
+       private String summary, description;
+       private Operation get, put, post, delete, options, head, patch, trace;
+       private List<Server> servers;
+       private List<Parameter> parameters;
+
+       /**
+        * Default constructor.
+        */
+       public PathItem() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public PathItem(PathItem copyFrom) {
+               super(copyFrom);
+               this.summary = copyFrom.summary;
+               this.description = copyFrom.description;
+               this.get = copyFrom.get;
+               this.put = copyFrom.put;
+               this.post = copyFrom.post;
+               this.delete = copyFrom.delete;
+               this.options = copyFrom.options;
+               this.head = copyFrom.head;
+               this.patch = copyFrom.patch;
+               this.trace = copyFrom.trace;
+               this.servers = copyOf(copyFrom.servers);
+               this.parameters = copyOf(copyFrom.parameters);
+       }
+
+       /**
+        * Returns the summary.
+        *
+        * @return The summary.
+        */
+       public String getSummary() {
+               return summary;
+       }
+
+       /**
+        * Sets the summary.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setSummary(String value) {
+               this.summary = value;
+               return this;
+       }
+
+       /**
+        * Returns the description.
+        *
+        * @return The description.
+        */
+       public String getDescription() {
+               return description;
+       }
+
+       /**
+        * Sets the description.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setDescription(String value) {
+               this.description = value;
+               return this;
+       }
+
+       /**
+        * Returns the GET operation.
+        *
+        * @return The GET operation.
+        */
+       public Operation getGet() {
+               return get;
+       }
+
+       /**
+        * Sets the GET operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setGet(Operation value) {
+               this.get = value;
+               return this;
+       }
+
+       /**
+        * Returns the PUT operation.
+        *
+        * @return The PUT operation.
+        */
+       public Operation getPut() {
+               return put;
+       }
+
+       /**
+        * Sets the PUT operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setPut(Operation value) {
+               this.put = value;
+               return this;
+       }
+
+       /**
+        * Returns the POST operation.
+        *
+        * @return The POST operation.
+        */
+       public Operation getPost() {
+               return post;
+       }
+
+       /**
+        * Sets the POST operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setPost(Operation value) {
+               this.post = value;
+               return this;
+       }
+
+       /**
+        * Returns the DELETE operation.
+        *
+        * @return The DELETE operation.
+        */
+       public Operation getDelete() {
+               return delete;
+       }
+
+       /**
+        * Sets the DELETE operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setDelete(Operation value) {
+               this.delete = value;
+               return this;
+       }
+
+       /**
+        * Returns the OPTIONS operation.
+        *
+        * @return The OPTIONS operation.
+        */
+       public Operation getOptions() {
+               return options;
+       }
+
+       /**
+        * Sets the OPTIONS operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setOptions(Operation value) {
+               this.options = value;
+               return this;
+       }
+
+       /**
+        * Returns the HEAD operation.
+        *
+        * @return The HEAD operation.
+        */
+       public Operation getHead() {
+               return head;
+       }
+
+       /**
+        * Sets the HEAD operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setHead(Operation value) {
+               this.head = value;
+               return this;
+       }
+
+       /**
+        * Returns the PATCH operation.
+        *
+        * @return The PATCH operation.
+        */
+       public Operation getPatch() {
+               return patch;
+       }
+
+       /**
+        * Sets the PATCH operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setPatch(Operation value) {
+               this.patch = value;
+               return this;
+       }
+
+       /**
+        * Returns the TRACE operation.
+        *
+        * @return The TRACE operation.
+        */
+       public Operation getTrace() {
+               return trace;
+       }
+
+       /**
+        * Sets the TRACE operation.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setTrace(Operation value) {
+               this.trace = value;
+               return this;
+       }
+
+       /**
+        * Returns the servers list.
+        *
+        * @return The servers list.
+        */
+       public List<Server> getServers() {
+               return servers;
+       }
+
+       /**
+        * Sets the servers list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setServers(List<Server> value) {
+               this.servers = value;
+               return this;
+       }
+
+       /**
+        * Returns the parameters list.
+        *
+        * @return The parameters list.
+        */
+       public List<Parameter> getParameters() {
+               return parameters;
+       }
+
+       /**
+        * Sets the parameters list.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public PathItem setParameters(List<Parameter> value) {
+               this.parameters = value;
+               return this;
+       }
+}
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SchemaInfo.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SchemaInfo.java
index e1c51ca84..3f68e1e22 100644
--- 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SchemaInfo.java
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SchemaInfo.java
@@ -18,7 +18,6 @@ import static org.apache.juneau.internal.ConverterUtils.*;
 import java.util.*;
 
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.internal.*;
 
@@ -1280,7 +1279,7 @@ public class SchemaInfo extends OpenApiElement {
        /**
         * Resolves any <js>"$ref"</js> attributes in this element.
         *
-        * @param swagger The swagger document containing the definitions.
+        * @param openApi The swagger document containing the definitions.
         * @param refStack Keeps track of previously-visited references so that 
we don't cause recursive loops.
         * @param maxDepth
         *      The maximum depth to resolve references.
@@ -1290,26 +1289,27 @@ public class SchemaInfo extends OpenApiElement {
         *      This object with references resolved.
         *      <br>May or may not be the same object.
         */
-       public SchemaInfo resolveRefs(Swagger swagger, Deque<String> refStack, 
int maxDepth) {
+       public SchemaInfo resolveRefs(OpenApi openApi, Deque<String> refStack, 
int maxDepth) {
 
                if (ref != null) {
                        if (refStack.contains(ref) || refStack.size() >= 
maxDepth)
                                return this;
                        refStack.addLast(ref);
-                       var r = swagger.findRef(ref, 
SchemaInfo.class).resolveRefs(swagger, refStack, maxDepth);
+                       var r = openApi.findRef(ref, SchemaInfo.class);
+                       r = r.resolveRefs(openApi, refStack, maxDepth);
                        refStack.removeLast();
                        return r;
                }
 
                if (items != null)
-                       items = items.resolveRefs(swagger, refStack, maxDepth);
+                       items = items.resolveRefs(openApi, refStack, maxDepth);
 
                if (properties != null)
                        for (var e : properties.entrySet())
-                               e.setValue(e.getValue().resolveRefs(swagger, 
refStack, maxDepth));
+                               e.setValue(e.getValue().resolveRefs(openApi, 
refStack, maxDepth));
 
                if (additionalProperties != null)
-                       additionalProperties = 
additionalProperties.resolveRefs(swagger, refStack, maxDepth);
+                       additionalProperties = 
additionalProperties.resolveRefs(openApi, refStack, maxDepth);
 
                this.example = null;
 
diff --git 
a/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
new file mode 100644
index 000000000..8dac859f5
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-openapi3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
@@ -0,0 +1,83 @@
+// 
***************************************************************************************************************************
+// * 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.bean.openapi3;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Lists the required security schemes for this operation.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#jrs.OpenApi">Overview &gt; juneau-rest-server 
&gt; OpenAPI</a>
+ * </ul>
+ */
+@Bean(properties="*")
+@FluentSetters
+public class SecurityRequirement extends OpenApiElement {
+
+       private Map<String,List<String>> requirements;
+
+       /**
+        * Default constructor.
+        */
+       public SecurityRequirement() {}
+
+       /**
+        * Copy constructor.
+        *
+        * @param copyFrom The object to copy.
+        */
+       public SecurityRequirement(SecurityRequirement copyFrom) {
+               super(copyFrom);
+               this.requirements = copyOf(copyFrom.requirements);
+       }
+
+       /**
+        * Returns the security requirements map.
+        *
+        * @return The security requirements map.
+        */
+       public Map<String,List<String>> getRequirements() {
+               return requirements;
+       }
+
+       /**
+        * Sets the security requirements map.
+        *
+        * @param value The new value for this property.
+        * @return This object.
+        */
+       public SecurityRequirement setRequirements(Map<String,List<String>> 
value) {
+               this.requirements = value;
+               return this;
+       }
+
+       /**
+        * Adds a security requirement.
+        *
+        * @param schemeName The security scheme name.
+        * @param scopes The required scopes.
+        * @return This object.
+        */
+       public SecurityRequirement addRequirement(String schemeName, String... 
scopes) {
+               if (requirements == null)
+                       requirements = new LinkedHashMap<>();
+               requirements.put(schemeName, Arrays.asList(scopes));
+               return this;
+       }
+}
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
 
b/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
index 416628883..5cbf6c881 100755
--- 
a/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/a/rttests/DTOs_RoundTripTest.java
@@ -16,7 +16,6 @@ import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import org.apache.juneau.bean.jsonschema.*;
-import org.apache.juneau.dto.jsonschema.*;
 import org.junit.jupiter.params.*;
 import org.junit.jupiter.params.provider.*;
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/atom/AtomTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/atom/AtomTest.java
similarity index 99%
rename from juneau-utest/src/test/java/org/apache/juneau/dto/atom/AtomTest.java
rename to juneau-utest/src/test/java/org/apache/juneau/bean/atom/AtomTest.java
index f150fdaf2..65ec43495 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/atom/AtomTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/bean/atom/AtomTest.java
@@ -10,7 +10,7 @@
 // * "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.dto.atom;
+package org.apache.juneau.bean.atom;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.atom.AtomBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.net.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.atom.*;
 import org.apache.juneau.xml.*;
 import org.junit.jupiter.api.*;
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5BasicTest.java
similarity index 96%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5BasicTest.java
index 0d2ac4f34..044c521a9 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5BasicTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5BasicTest.java
@@ -10,13 +10,12 @@
 // * "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.dto.html5;
+package org.apache.juneau.bean.html5;
 
 import static org.apache.juneau.bean.html5.HtmlBuilder.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.html5.*;
 import org.junit.jupiter.api.*;
 
 class Html5BasicTest extends SimpleTestBase {
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5Template_ComboRoundTripTest.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5Template_ComboRoundTripTest.java
similarity index 97%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5Template_ComboRoundTripTest.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5Template_ComboRoundTripTest.java
index eb25df6f6..c1c8689c2 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5Template_ComboRoundTripTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5Template_ComboRoundTripTest.java
@@ -10,7 +10,7 @@
 // * "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.dto.html5;
+package org.apache.juneau.bean.html5;
 
 import static org.apache.juneau.assertions.Verify.*;
 import static org.apache.juneau.bean.html5.HtmlBuilder.*;
@@ -19,7 +19,6 @@ import java.lang.reflect.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.bean.html5.*;
 
 /**
  * Tests serialization of HTML5 templates.
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5_ComboRoundTripTest.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5_ComboRoundTripTest.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5_ComboRoundTripTest.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5_ComboRoundTripTest.java
index e6e6dabc3..db07b9193 100755
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/html5/Html5_ComboRoundTripTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/html5/Html5_ComboRoundTripTest.java
@@ -10,7 +10,7 @@
 // * "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.dto.html5;
+package org.apache.juneau.bean.html5;
 
 import static org.apache.juneau.assertions.Verify.*;
 import static org.apache.juneau.bean.html5.HtmlBuilder.*;
@@ -22,8 +22,6 @@ import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.html5.*;
-import org.apache.juneau.bean.html5.Map;
 import org.apache.juneau.internal.*;
 
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/jsonschema/JsonSchema_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/jsonschema/JsonSchema_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/jsonschema/JsonSchema_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/jsonschema/JsonSchema_Test.java
index 31e3c2a7b..53268125b 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/jsonschema/JsonSchema_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/jsonschema/JsonSchema_Test.java
@@ -10,14 +10,13 @@
 // * "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.dto.jsonschema;
+package org.apache.juneau.bean.jsonschema;
 
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.net.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.jsonschema.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Contact_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Contact_Test.java
similarity index 97%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Contact_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Contact_Test.java
index 03daac638..534e79043 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Contact_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Contact_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.net.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ExternalDocumentation_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ExternalDocumentation_Test.java
similarity index 97%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ExternalDocumentation_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ExternalDocumentation_Test.java
index 56aadd6ff..3b11ced5d 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ExternalDocumentation_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ExternalDocumentation_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.net.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/HeaderInfo_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/HeaderInfo_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/HeaderInfo_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/HeaderInfo_Test.java
index 78ec56b13..a159b4d37 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/HeaderInfo_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/HeaderInfo_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Info_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Info_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Info_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Info_Test.java
index 8f55a589a..2e692c14d 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Info_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Info_Test.java
@@ -10,14 +10,13 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Items_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Items_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Items_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Items_Test.java
index 31a0513a4..c45067b36 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Items_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Items_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/License_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/License_Test.java
similarity index 97%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/License_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/License_Test.java
index 2baf0d94e..4188870cf 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/License_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/License_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.net.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Operation_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Operation_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Operation_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Operation_Test.java
index 374fe7750..cf5f922e7 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Operation_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Operation_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ParameterInfo_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ParameterInfo_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ParameterInfo_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ParameterInfo_Test.java
index 8d42167f5..db678c517 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ParameterInfo_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ParameterInfo_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ResponseInfo_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ResponseInfo_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ResponseInfo_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ResponseInfo_Test.java
index a131267c4..d61113bcb 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/ResponseInfo_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/ResponseInfo_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SchemaInfo_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SchemaInfo_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SchemaInfo_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SchemaInfo_Test.java
index 186c13aec..331f839e4 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SchemaInfo_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SchemaInfo_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SecurityScheme_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SecurityScheme_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SecurityScheme_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SecurityScheme_Test.java
index bf4f45187..a8414f42d 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SecurityScheme_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SecurityScheme_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SwaggerBuilder_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SwaggerBuilder_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SwaggerBuilder_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SwaggerBuilder_Test.java
index 8d01fdefe..0e7041cb4 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/SwaggerBuilder_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/SwaggerBuilder_Test.java
@@ -10,13 +10,12 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.junit.jupiter.api.*;
 
 /**
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Swagger_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Swagger_Test.java
similarity index 99%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Swagger_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Swagger_Test.java
index 2aa1f77e6..568fb07bd 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Swagger_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Swagger_Test.java
@@ -10,7 +10,7 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
@@ -19,8 +19,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
-import org.apache.juneau.bean.swagger.Tag;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Tag_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Tag_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Tag_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Tag_Test.java
index ed41be930..32ca4883d 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Tag_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Tag_Test.java
@@ -10,14 +10,13 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.Tag;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Xml_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Xml_Test.java
similarity index 98%
rename from 
juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Xml_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Xml_Test.java
index 01bfd233c..cda73a98a 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/dto/swagger/Xml_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/bean/swagger/Xml_Test.java
@@ -10,13 +10,12 @@
 // * "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.dto.swagger;
+package org.apache.juneau.bean.swagger;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.bean.swagger.*;
 import org.apache.juneau.common.internal.*;
 import org.apache.juneau.json.*;
 import org.junit.jupiter.api.*;

Reply via email to