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 2316e40 Swagger UI enhancements.
2316e40 is described below
commit 2316e4075b98c0a2e9c5186923423ecac0a4565f
Author: JamesBognar <[email protected]>
AuthorDate: Sun Apr 8 06:33:27 2018 -0700
Swagger UI enhancements.
---
.../org/apache/juneau/dto/swagger/HeaderInfo.java | 12 ++--
.../java/org/apache/juneau/dto/swagger/Items.java | 39 +++++++++--
.../apache/juneau/dto/swagger/ParameterInfo.java | 10 ++-
.../apache/juneau/dto/swagger/ResponseInfo.java | 10 ++-
.../org/apache/juneau/dto/swagger/SchemaInfo.java | 16 +++--
.../apache/juneau/dto/swagger/ui/SwaggerUI.java | 81 +++++++++++++++++-----
.../jsonschema/JsonSchemaSerializerSession.java | 17 ++---
.../examples/rest/petstore/PetStoreResource.java | 6 ++
.../apache/juneau/rest/BasicRestInfoProvider.java | 4 +-
9 files changed, 144 insertions(+), 51 deletions(-)
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/HeaderInfo.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/HeaderInfo.java
index 98bd49c..e4316fa 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/HeaderInfo.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/HeaderInfo.java
@@ -1142,23 +1142,27 @@ public class HeaderInfo extends SwaggerElement {
*
* @param swagger 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.
+ * <br>After that level is reached, <code>$ref</code> references
will be left alone.
+ * <br>Useful if you have very complex models and you don't want
your swagger page to be overly-complex.
* @return
* This object with references resolved.
* <br>May or may not be the same object.
*/
- public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack) {
+ public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack,
int maxDepth) {
if (ref != null) {
- if (refStack.contains(ref) || refStack.size() > 2)
+ if (refStack.contains(ref) || refStack.size() >=
maxDepth)
return this;
refStack.addLast(ref);
- HeaderInfo r = swagger.findRef(ref,
HeaderInfo.class).resolveRefs(swagger, refStack);
+ HeaderInfo r = swagger.findRef(ref,
HeaderInfo.class).resolveRefs(swagger, refStack, maxDepth);
refStack.removeLast();
return r;
}
if (items != null)
- items = items.resolveRefs(swagger, refStack);
+ items = items.resolveRefs(swagger, refStack, maxDepth);
return this;
}
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Items.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Items.java
index 35c63bf..544c492 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Items.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Items.java
@@ -1115,26 +1115,55 @@ public class Items extends SwaggerElement {
*
* @param swagger 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.
+ * <br>After that level is reached, <code>$ref</code> references
will be left alone.
+ * <br>Useful if you have very complex models and you don't want
your swagger page to be overly-complex.
* @return
* This object with references resolved.
* <br>May or may not be the same object.
*/
- public Items resolveRefs(Swagger swagger, Deque<String> refStack) {
+ public Items resolveRefs(Swagger swagger, Deque<String> refStack, int
maxDepth) {
if (ref != null) {
- if (refStack.contains(ref) || refStack.size() > 2)
+ if (refStack.contains(ref) || refStack.size() >=
maxDepth)
return this;
refStack.addLast(ref);
- Items r = swagger.findRef(ref,
Items.class).resolveRefs(swagger, refStack);
+ Items r = swagger.findRef(ref,
Items.class).resolveRefs(swagger, refStack, maxDepth);
refStack.removeLast();
return r;
}
-
+
+ set("properties", resolveRefs(get("properties"), swagger,
refStack, maxDepth));
+
if (items != null)
- items = items.resolveRefs(swagger, refStack);
+ items = items.resolveRefs(swagger, refStack, maxDepth);
set("example", null);
return this;
}
+
+ /* Resolve references in extra attributes */
+ private Object resolveRefs(Object o, Swagger swagger, Deque<String>
refStack, int maxDepth) {
+ if (o instanceof ObjectMap) {
+ ObjectMap om = (ObjectMap)o;
+ String ref = om.getString("$ref");
+ if (ref != null) {
+ if (refStack.contains(ref) || refStack.size()
>= maxDepth)
+ return o;
+ refStack.addLast(ref);
+ Object o2 = swagger.findRef(ref, Object.class);
+ o2 = resolveRefs(o2, swagger, refStack,
maxDepth);
+ refStack.removeLast();
+ return o2;
+ }
+ for (Map.Entry<String,Object> e : om.entrySet())
+ e.setValue(resolveRefs(e.getValue(), swagger,
refStack, maxDepth));
+ }
+ if (o instanceof ObjectList)
+ for (ListIterator<Object> li =
((ObjectList)o).listIterator(); li.hasNext();)
+ li.set(resolveRefs(li.next(), swagger,
refStack, maxDepth));
+ return o;
+ }
}
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
index 3be783a..9034c5d 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
@@ -1582,17 +1582,21 @@ public class ParameterInfo extends SwaggerElement {
*
* @param swagger 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.
+ * <br>After that level is reached, <code>$ref</code> references
will be left alone.
+ * <br>Useful if you have very complex models and you don't want
your swagger page to be overly-complex.
* @return
* This object with references resolved.
* <br>May or may not be the same object.
*/
- public ParameterInfo resolveRefs(Swagger swagger, Deque<String>
refStack) {
+ public ParameterInfo resolveRefs(Swagger swagger, Deque<String>
refStack, int maxDepth) {
if (schema != null)
- schema = schema.resolveRefs(swagger, refStack);
+ schema = schema.resolveRefs(swagger, refStack,
maxDepth);
if (items != null)
- items = items.resolveRefs(swagger, refStack);
+ items = items.resolveRefs(swagger, refStack, maxDepth);
return this;
}
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ResponseInfo.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ResponseInfo.java
index 6923368..5dd1da6 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ResponseInfo.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ResponseInfo.java
@@ -441,18 +441,22 @@ public class ResponseInfo extends SwaggerElement {
*
* @param swagger 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.
+ * <br>After that level is reached, <code>$ref</code> references
will be left alone.
+ * <br>Useful if you have very complex models and you don't want
your swagger page to be overly-complex.
* @return
* This object with references resolved.
* <br>May or may not be the same object.
*/
- public ResponseInfo resolveRefs(Swagger swagger, Deque<String>
refStack) {
+ public ResponseInfo resolveRefs(Swagger swagger, Deque<String>
refStack, int maxDepth) {
if (schema != null)
- schema = schema.resolveRefs(swagger, refStack);
+ schema = schema.resolveRefs(swagger, refStack,
maxDepth);
if (headers != null)
for (Map.Entry<String,HeaderInfo> e :
headers.entrySet())
- e.setValue(e.getValue().resolveRefs(swagger,
refStack));
+ e.setValue(e.getValue().resolveRefs(swagger,
refStack, maxDepth));
return this;
}
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/SchemaInfo.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/SchemaInfo.java
index 4ec8abb..8e970b2 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/SchemaInfo.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/SchemaInfo.java
@@ -1510,30 +1510,34 @@ public class SchemaInfo extends SwaggerElement {
*
* @param swagger 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.
+ * <br>After that level is reached, <code>$ref</code> references
will be left alone.
+ * <br>Useful if you have very complex models and you don't want
your swagger page to be overly-complex.
* @return
* This object with references resolved.
* <br>May or may not be the same object.
*/
- public SchemaInfo resolveRefs(Swagger swagger, Deque<String> refStack) {
+ public SchemaInfo resolveRefs(Swagger swagger, Deque<String> refStack,
int maxDepth) {
if (ref != null) {
- if (refStack.contains(ref) || refStack.size() > 2)
+ if (refStack.contains(ref) || refStack.size() >=
maxDepth)
return this;
refStack.addLast(ref);
- SchemaInfo r = swagger.findRef(ref,
SchemaInfo.class).resolveRefs(swagger, refStack);
+ SchemaInfo r = swagger.findRef(ref,
SchemaInfo.class).resolveRefs(swagger, refStack, maxDepth);
refStack.removeLast();
return r;
}
if (items != null)
- items = items.resolveRefs(swagger, refStack);
+ items = items.resolveRefs(swagger, refStack, maxDepth);
if (properties != null)
for (Map.Entry<String,SchemaInfo> e :
properties.entrySet())
- e.setValue(e.getValue().resolveRefs(swagger,
refStack));
+ e.setValue(e.getValue().resolveRefs(swagger,
refStack, maxDepth));
if (additionalProperties != null)
- additionalProperties =
additionalProperties.resolveRefs(swagger, refStack);
+ additionalProperties =
additionalProperties.resolveRefs(swagger, refStack, maxDepth);
this.example = null;
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
index d5e76c8..177e5ad 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
@@ -30,6 +30,42 @@ import org.apache.juneau.utils.*;
*/
public class SwaggerUI extends PojoSwap<Swagger,Div> {
+
//-------------------------------------------------------------------------------------------------------------------
+ // Configurable properties
+
//-------------------------------------------------------------------------------------------------------------------
+
+ private static final String PREFIX = "SwaggerUI.";
+
+ /**
+ * Configuration property: Resolve <code>$ref</code> references in
schema up to the specified depth.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"SwaggerUI.resolveRefsMaxDepth.i"</js>
+ * <li><b>Data type:</b> <code>Integer</code>
+ * <li><b>Default:</b> <code>1</code>
+ * <li><b>Session-overridable:</b> <jk>true</jk>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * Defines the maximum recursive depth to resolve <code>$ref</code>
variables in schema infos.
+ * <br>The default <code>1</code> means only resolve the first
reference encountered.
+ * <br>A value of <code>0</code> disables reference resolution
altogether.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Resolve schema references up to 5 levels deep.
+ * <ja>@RestResource</ja>(
+ * properties={
+ *
<ja>@Property</ja>(name=<jsf>SWAGGERUI_resolveRefsMaxDepth</jsf>,
value=<js>"5"</js>)
+ * }
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ */
+ public static final String SWAGGERUI_resolveRefsMaxDepth = PREFIX +
"resolveRefsMaxDepth.i";
+
+
static final ClasspathResourceManager RESOURCES = new
ClasspathResourceManager(SwaggerUI.class);
@Override
@@ -37,10 +73,21 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
return new MediaType[] {MediaType.HTML};
}
+ private static final class Session {
+ final int resolveRefsMaxDepth;
+ final Swagger swagger;
+
+ Session(BeanSession bs, Swagger swagger) {
+ this.swagger = swagger.copy();
+ this.resolveRefsMaxDepth =
bs.getProperty(SWAGGERUI_resolveRefsMaxDepth, Integer.class, 1);
+ System.err.println("resolveRefsMaxDepth=" +
resolveRefsMaxDepth);
+ }
+ }
+
@Override
- public Div swap(BeanSession session, Swagger s) throws Exception {
+ public Div swap(BeanSession beanSession, Swagger swagger) throws
Exception {
- s = s.copy();
+ Session s = new Session(beanSession, swagger);
Div outer = div(
style(RESOURCES.getString("SwaggerUI.css")),
@@ -51,8 +98,8 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
// Operations without tags are rendered first.
outer.child(div()._class("tag-block
tag-block-open").children(tagBlockContents(s, null)));
- if (s.hasTags()) {
- for (Tag t : s.getTags()) {
+ if (s.swagger.hasTags()) {
+ for (Tag t : s.swagger.getTags()) {
Div tagBlock = div()._class("tag-block
tag-block-open").children(
tagBlockSummary(t),
tagBlockContents(s, t)
@@ -61,7 +108,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
}
}
- if (s.hasDefinitions()) {
+ if (s.swagger.hasDefinitions()) {
Div modelBlock = div()._class("tag-block").children(
modelsBlockSummary(),
modelsBlockContents(s)
@@ -73,10 +120,10 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
}
// Creates the informational summary before the ops.
- private Table header(Swagger s) {
+ private Table header(Session s) {
Table table = table()._class("header");
- Info info = s.getInfo();
+ Info info = s.swagger.getInfo();
if (info != null) {
if (info.hasVersion())
@@ -108,7 +155,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
table.child(tr(th("License:"),td(child)));
}
- ExternalDocumentation ed = s.getExternalDocs();
+ ExternalDocumentation ed = s.swagger.getExternalDocs();
if (ed != null) {
Object child = ed.hasUrl() ? a(ed.getUrl(),
ed.hasDescription() ? ed.getDescription() : ed.getUrl()) : ed.getDescription();
table.child(tr(th("Docs:"),td(child)));
@@ -130,10 +177,10 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
}
// Creates the contents under the "pet Everything about your Pets
ext-link" header.
- private Div tagBlockContents(Swagger s, Tag t) {
+ private Div tagBlockContents(Session s, Tag t) {
Div tagBlockContents = div()._class("tag-block-contents");
- for (Map.Entry<String,Map<String,Operation>> e :
s.getPaths().entrySet()) {
+ for (Map.Entry<String,Map<String,Operation>> e :
s.swagger.getPaths().entrySet()) {
String path = e.getKey();
for (Map.Entry<String,Operation> e2 :
e.getValue().entrySet()) {
String opName = e2.getKey();
@@ -146,7 +193,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
return tagBlockContents;
}
- private Div opBlock(Swagger s, String path, String opName, Operation
op) {
+ private Div opBlock(Session s, String path, String opName, Operation
op) {
String opNameLc = op.isDeprecated() ? "deprecated" :
opName.toLowerCase();
return div()._class("op-block op-block-closed " +
opNameLc).children(
@@ -163,7 +210,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
).onclick("toggleOpBlock(this)");
}
- private Div tableContainer(Swagger s, Operation op) {
+ private Div tableContainer(Session s, Operation op) {
Div tableContainer = div()._class("table-container");
if (op.hasDescription())
@@ -220,7 +267,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
return tableContainer;
}
- private Div headers(Swagger s, ResponseInfo ri) {
+ private Div headers(Session s, ResponseInfo ri) {
if (! ri.hasHeaders())
return null;
@@ -246,7 +293,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
return headers;
}
- private Div examples(Swagger swagger, SchemaInfo si, Map<String,?>
examples) {
+ private Div examples(Session s, SchemaInfo si, Map<String,?> examples) {
if (si == null && examples == null)
return null;
@@ -258,7 +305,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
if (si != null) {
select.child(option("model","model"));
- div.child(div(si.copy().resolveRefs(swagger, new
ArrayDeque<String>()))._class("model active").attr("data-name", "model"));
+ div.child(div(si.copy().resolveRefs(s.swagger, new
ArrayDeque<String>(), s.resolveRefsMaxDepth))._class("model
active").attr("data-name", "model"));
}
if (examples != null) {
@@ -279,9 +326,9 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
}
// Creates the contents under the "Model" header.
- private Div modelsBlockContents(Swagger s) {
+ private Div modelsBlockContents(Session s) {
Div modelBlockContents = div()._class("tag-block-contents");
- for (Map.Entry<String,ObjectMap> e :
s.getDefinitions().entrySet())
+ for (Map.Entry<String,ObjectMap> e :
s.swagger.getDefinitions().entrySet())
modelBlockContents.child(modelBlock(e.getKey(),
e.getValue()));
return modelBlockContents;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
index e078030..c9032a7 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
@@ -114,19 +114,14 @@ public class JsonSchemaSerializerSession extends
JsonSerializerSession {
boolean useDef = useBeanDefs && sType.isBean() && pNames ==
null;
- if (useDef && defs.containsKey(getBeanDefId(sType))) {
- ObjectMap schema = defs.get(getBeanDefId(sType));
-
- // If we previously encountered this bean in a
collection/array, then it may not have
- // the example and description associated with it, so
add it now.
- if (! schema.containsKey("x-example"))
- schema.appendIf(true, true, true, "x-example",
getExample(sType, BEAN, exampleAdded));
- if (! schema.containsKey("description"))
- schema.appendIf(true, true, true,
"description", getDescription(sType, BEAN, exampleAdded));
-
- return new ObjectMap().append("$ref",
getBeanDefUri(sType));
+ if (useDef) {
+ exampleAdded = false;
+ descriptionAdded = false;
}
+ if (useDef && defs.containsKey(getBeanDefId(sType)))
+ return new ObjectMap().append("$ref",
getBeanDefUri(sType));
+
ObjectMap ds =
defaultSchemas.get(sType.getInnerClass().getName());
if (ds != null && ds.containsKey("type"))
return out.appendAll(ds);
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
index 16658f7..fe93b0a 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
@@ -12,6 +12,8 @@
//
***************************************************************************************************************************
package org.apache.juneau.examples.rest.petstore;
+import static org.apache.juneau.dto.swagger.ui.SwaggerUI.*;
+
import java.util.*;
import org.apache.juneau.internal.*;
@@ -43,6 +45,10 @@ import org.apache.juneau.rest.widget.*;
"source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/petstore/$R{servletClassSimple}.java"
}
),
+ properties= {
+ // Resolve recursive references when showing schema info in the
swagger.
+ @Property(name=SWAGGERUI_resolveRefsMaxDepth, value="99")
+ },
swagger="$F{PetStoreResource.json}"
)
public class PetStoreResource extends BasicRestServletJena {
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index 8f18b2b..887cc02 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -551,8 +551,8 @@ public class BasicRestInfoProvider implements
RestInfoProvider {
if (example == null) {
ObjectMap schema = resolve(js,
piri.getObjectMap("schema"));
- if (schema != null)
- example = schema.get("example");
+ if (schema != null)
+ example = schema.getWithDefault("example",
schema.get("x-example"));
}
if (example == null)
--
To stop receiving notification emails like this one, please contact
[email protected].