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 c1f829c Javadocs c1f829c is described below commit c1f829c4b1646cc0d296ba12895de4be7e119f26 Author: JamesBognar <jamesbog...@apache.org> AuthorDate: Fri Aug 31 09:23:18 2018 -0400 Javadocs --- .../doc-files/juneau-rest-server.Swagger.1.png | Bin 0 -> 174380 bytes .../doc-files/juneau-rest-server.Swagger.2.png | Bin 0 -> 194455 bytes .../doc-files/juneau-rest-server.Swagger.3.png | Bin 0 -> 79498 bytes .../doc-files/juneau-rest-server.Swagger.4.png | Bin 0 -> 99968 bytes .../doc-files/juneau-rest-server.Swagger.5.png | Bin 0 -> 63056 bytes juneau-doc/src/main/javadoc/overview.html | 339 +++++++++++++++++++- .../Topics/07.juneau-rest-server/26.Swagger.html | 340 ++++++++++++++++++++- .../doc-files/juneau-rest-server.Swagger.1.png | Bin 0 -> 174380 bytes .../doc-files/juneau-rest-server.Swagger.2.png | Bin 0 -> 194455 bytes .../doc-files/juneau-rest-server.Swagger.3.png | Bin 0 -> 79498 bytes .../doc-files/juneau-rest-server.Swagger.4.png | Bin 0 -> 99968 bytes .../doc-files/juneau-rest-server.Swagger.5.png | Bin 0 -> 63056 bytes .../apache/juneau/examples/rest/petstore/Pet.java | 12 +- .../juneau/examples/rest/petstore/PetStore.java | 42 +-- .../examples/rest/petstore/PetStoreResource.java | 43 ++- .../rest/petstore/{Tag.java => PetTag.java} | 20 +- .../org/apache/juneau/rest/BasicRestServlet.java | 54 ++-- .../java/org/apache/juneau/rest/RestContext.java | 14 - .../org/apache/juneau/rest/RestJavaMethod.java | 36 +-- .../java/org/apache/juneau/rest/RestRequest.java | 14 + .../org/apache/juneau/rest/SwaggerGenerator.java | 2 +- 21 files changed, 783 insertions(+), 133 deletions(-) diff --git a/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.1.png b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.1.png new file mode 100644 index 0000000..69b656f Binary files /dev/null and b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.1.png differ diff --git a/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.2.png b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.2.png new file mode 100644 index 0000000..284fa85 Binary files /dev/null and b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.2.png differ diff --git a/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.3.png b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.3.png new file mode 100644 index 0000000..c642c41 Binary files /dev/null and b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.3.png differ diff --git a/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.4.png b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.4.png new file mode 100644 index 0000000..42762e0 Binary files /dev/null and b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.4.png differ diff --git a/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.5.png b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.5.png new file mode 100644 index 0000000..d889fa7 Binary files /dev/null and b/juneau-doc/src/main/javadoc/doc-files/juneau-rest-server.Swagger.5.png differ diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html index b23e47f..497d2b5 100644 --- a/juneau-doc/src/main/javadoc/overview.html +++ b/juneau-doc/src/main/javadoc/overview.html @@ -18342,36 +18342,345 @@ One of the most useful features of Juneau is the ability to generate Swagger-based OPTIONS pages for self-documenting designs (i.e. REST interfaces that document themselves). </p> -<h5 class='figure'>OPTIONS page for HelloWorld sample resource</h5> -<p class='bpcode w800'> - http://localhost:10000/helloWorld/?method=OPTIONS +<p> + As described previously, the <code>PetStore</code> example provides an example of auto-generated Swagger JSON: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.1.png'> +<p> + Using {@link org.apache.juneau.dto.swagger.ui.SwaggerUI}, we're able to render that JSON as a Swagger user interface: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.2.png'> +<p> + Any subclass of {@link org.apache.juneau.rest.BasicRestServlet} gets an auto-generated Swagger UI when performing an <code>OPTIONS</code> + request with <code>Accept: text/html</code>. +</p> +<p> + The underlying mechanics are simple. + The {@link org.apache.juneau.rest.BasicRestServlet#getOptions(RestRequest)} method returns a {@link org.apache.juneau.dto.swagger.Swagger} bean + consisting of information gathered from annotations and other sources. + Then that bean is swapped for a {@link org.apache.juneau.dto.swagger.ui.SwaggerUI} bean when rendered as HTML. </p> -<img class='bordered w800' src='doc-files/juneau-rest-server.OptionsPages.1.png'> <p> - The {@link org.apache.juneau.rest.BasicRestServlet} class implements the page by creating a method - mapped to the <l>OPTIONS</l> HTTP method that simply returns a Swagger bean: + Here's the class that defines the behavior: </p> <p class='bpcode w800'> - <ja>@RestResource</ja>(...) - <jk>public class</jk> BasicRestServlet <jk>extends</jk> RestServlet { - - <ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>, - summary=<js>"Resource options"</js>, + <ja>@RestResource</ja>( + + <jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter.</jc> + allowedMethodParams=<js>"OPTIONS"</js>, + + ... + ) + <jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig { + + <jd>/** + * [OPTIONS /*] - Show resource options. + * + * <ja>@param</ja> req The HTTP request. + * <ja>@return</ja> A bean containing the contents for the OPTIONS page. + */</jd> + <ja>@RestMethod</ja>(name=OPTIONS, path=<js>"/*"</js>, + summary=<js>"Swagger documentation"</js>, + description=<js>"Swagger documentation for this resource."</js>, htmldoc=<ja>@HtmlDoc</ja>( + <jc>// Override the nav links for the swagger page.</jc> navlinks={ - <js>"back: servlet:/,"</js>, - <js>"json: servlet:/?method=OPTIONS&Accept=text/json&plainText=true"</js> - } + <js>"back: servlet:/"</js>, + <js>"json: servlet:/?method=OPTIONS&Accept=text/json&plainText=true"</js> + }, + <jc>// Never show aside contents of page inherited from class.</jc> + aside=<js>"NONE"</js> ) + + <jc>// POJO swaps to apply to all serializers/parsers.</jc> + pojoSwaps={ + <jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc> + <jc>// This is a per-media-type swap that only applies to text/html requests.</jc> + SwaggerUI.<jk>class</jk> + }, + + <jc>// Properties to apply to all serializers/parsers and REST-specific API objects.</jc> + properties={ + <jc>// Add descriptions to the following types when not specified:</jc> + <ja>@Property</ja>(name=<jsf>JSONSCHEMA_addDescriptionsTo</jsf>, value=<js>"bean,collection,array,map,enum"</js>), + + <jc>// Add x-example to the following types:</jc> + <ja>@Property</ja>(name=<jsf>JSONSCHEMA_addExamplesTo</jsf>, value=<js>"bean,collection,array,map"</js>), + + <jc>// Don't generate schema information on the Swagger bean itself or HTML beans.</jc> + <ja>@Property</ja>(name=<jsf>INFOPROVIDER_ignoreTypes</jsf>, value=<js>"Swagger,org.apache.juneau.dto.html5.*"</js>) + }, + + <jc>// Shortcut for boolean properties.</jc> + flags={ + <jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc> + <jsf>JSONSCHEMA_useBeanDefs</jsf> + } ) <jk>public</jk> Swagger getOptions(RestRequest req) { + <jc>// Localized Swagger for this resource is available through the RestRequest object.</jc> <jk>return</jk> req.getSwagger(); } } </p> <p> - This page is constructed using the Info Provider API described next. + Let's look at the various parts of the <code>Petstore</code> application Swagger UI to see how they are defined. +</p> + +<h5 class='topic'>General Information</h5> +<p> + The top part of the page shows general information about the REST interface: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.3.png'> +<p> + The information is pulled from the {@link org.apache.juneau.rest.annotation.RestResource#swagger() @RestResource(swagger)} annotation. +</p> +<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=@ResourceSwagger(<js>"$F{PetStoreResource.json}"</js>), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + In this particular case, the Swagger is pulled in from a localized Swagger JSON file located in the + <code>org.apache.juneau.examples.rest.petstore</code> package using the {@link org.apache.juneau.rest.vars.FileVar $F} variable. +</p> +<h5 class='figure'>PetStoreResource.json</h5> +<p class='bpcode w800'> + { + <jok>"swagger"</jok>: <jov>"2.0"</jov>, + <jok>"info"</jok>: { + <jok>"version"</jok>: <jov>"1.0.0"</jov>, + <jok>"title"</jok>: <jov>"Swagger Petstore"</jov>, + <jok>"termsOfService"</jok>: <jov>"You are on your own."</jov>, + <jok>"contact"</jok>: { + <jok>"name"</jok>: <jov>"Juneau Development Team"</jov>, + <jok>"email"</jok>: <jov>"d...@juneau.apache.org"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + }, + <jok>"license"</jok>: { + <jok>"name"</jok>: <jov>"Apache 2.0"</jov>, + <jok>"url"</jok>: <jov>"http://www.apache.org/licenses/LICENSE-2.0.html"</jov> + } + }, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more about Juneau"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + }, + ... + } +</p> +<p> + Note that the {@link org.apache.juneau.rest.vars.FileVar $F} variable allows for request-locale-sensitive name matching so that you can provide + localized Swagger information. +</p> +<p> + The {@link org.apache.juneau.rest.vars.FileVar $F} variable simply expands to a string to fill the {@link org.apache.juneau.rest.annotation.ResourceSwagger#value() @ResourceSwagger(value)} + annotation. + You could equivalently embed JSON directly into your annotation like so: +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + <js>"{"</js>, + <js>"swagger: '2.0',"</js>, + <js>"version: '1.0.0',",</js>, + ... + <js>"}"</js> + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + However, a more typical scenario is to define all of your Swagger as annotations: +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + version=<js>"1.0.0"</js>, + title=<js>"Swagger Petstore"</js>, + termsOfService=<js>"You are on your own."</js>, + contact=<ja>@Contact</ja>( + name=<js>"Juneau Development Team"</js>, + email=<js>"d...@juneau.apache.org"</js>, + url=<js>"http://juneau.apache.org"</js> + ), + license=<ja>@License</ja>( + name=<js>"Apache 2.0"</js>, + url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js> + ), + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more about Juneau"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + All annotations support {@doc DefaultRestSvlVariables SVL variables}, so you could for example + pull localized strings from resource bundles using {@link org.apache.juneau.rest.vars.LocalizationVar $L} variables. +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + messages=<js>"nls/MyMessages"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + version=<js>"1.0.0"</js>, + title=<js>"$L{myTitle}"</js>, + termsOfService=<js>"$L{myTermsOfService}"</js>, + contact=<ja>@Contact</ja>( + name=<js>"$L{myTeam}"</js>, + email=<js>"d...@juneau.apache.org"</js>, + url=<js>"http://juneau.apache.org"</js> + ), + license=<ja>@License</ja>( + name=<js>"Apache 2.0"</js>, + url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js> + ), + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"$L{myExternalDocsDescription}"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + A third option is to define your Swagger information in your {@link org.apache.juneau.rest.annotation.RestResource#messages @RestResource(messages)} resource + bundle using predefined Swagger keywords: +</p> +<p class='bpcode w800'> + <mk>PetStoreResource.version</mk> = <mv>1.0.0</mv> + <mk>PetStoreResource.title</mk> = <mv>Swagger Petstore</mv> + <mk>PetStoreResource.termsOfService</mk> = <mv>You are on your own.</mv> + <mk>PetStoreResource.contact</mk> = <mv>{name:'Juneau Development Team', email:'d...@juneau.apache.org',...}</mv> + <mk>PetStoreResource.license</mk> = <mv>{name:'Apache 2.0',...}</mv> + <mk>PetStoreResource.externalDocs</mk> = <mv>{description:'Find out more about Juneau',...}</mv> +</p> +<p> + Information defined in multiple locations are merged into a single set of data. + When the same information is provided in multiple locations, the following order-of-precedence is used: +</p> +<ol> + <li>Java annotations + <li>Resource bundle + <li>Swagger JSON file +</ol> + +<h5 class='topic'>Tags</h5> +<p> + Tags allow you to group operations into general categories. + In the user interface, these can be expanded/collapsed by clicking on the tag sections. + <br>In the example below, the <code>pet</code> and <code>store</code> tag sections are collapsed + and the <code>user</code> section is not: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.4.png'> +<p> + Tags are also defined in the <ja>@ResourceSwagger</ja> annotation +</p> +<h5 class='figure'>PetStoreResource.json</h5> +<p class='bpcode w800'> + <jok>"tags"</jok>: [ + { + <jok>"name"</jok>: <jov>"pet"</jov>, + <jok>"description"</jok>: <jov>"Everything about your Pets"</jov>, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + } + }, + { + <jok>"name"</jok>: <jov>"store"</jov>, + <jok>"description"</jok>: <jov>"Access to Petstore orders"</jov> + }, + { + <jok>"name"</jok>: <jov>"user", + <jok>"description"</jok>: <jov>"Operations about user"</jov>, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more about our store"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + } + } + ], + +</p> +<p> + The annotation-only approach is shown here: +</p> +<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5> +<p class='bpcode w800'> + swagger=<ja>@ResourceSwagger</ja>( + ... + tags={ + <ja>@Tag</ja>( + name=<js>"pet"</js>, + description=<js>"Everything about your Pets"</js>, + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + <ja>@Tag</ja>( + name=<js>"store"</js>, + description=<js>"Access to Petstore orders"</js> + ), + <ja>@Tag</ja>( + name=<js>"user"</js>, + description=<js>"Operations about user"</js>, + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more about our store"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ) + } + ), +</p> +<p> + Tags are associated with operations using the {@link org.apache.juneau.rest.annotation.MethodSwagger#tags() @MethodSwagger(tags)} annotation: +</p> + +<h5 class='figure'>GET /user operation</h5> +<p class='bpcode w800'> + <ja>@RestMethod</ja>( + name=<jsf>GET</jsf>, + path=<js>"/user"</js>, + summary=<js>"Petstore users"</js>, + swagger=<ja>@MethodSwagger</ja>( + tags=<js>"user"</js> + ) + ) + <jk>public</jk> Collection<User> getUsers() <jk>throws</jk> NotAcceptable {...} +</p> +<p> + Operations can be mapped to multiple tags. +</p> +<p> + Tags are optional. + Operations not mapped to tags are listed in the UI before tagged operations. +</p> +<p> + For example, the <code>getTopPage()</code> method in <code>PetStoreResource</code> is not tagged, + as well as the <code>getOptions()</code> method inherited from <code>BaseRestServlet</code>, so these + show up at the top of the page: </p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.5.png'> <!-- ==================================================================================================== --> diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/26.Swagger.html b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/26.Swagger.html index d2b9f1c..825568c 100644 --- a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/26.Swagger.html +++ b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/26.Swagger.html @@ -19,33 +19,343 @@ One of the most useful features of Juneau is the ability to generate Swagger-based OPTIONS pages for self-documenting designs (i.e. REST interfaces that document themselves). </p> -<h5 class='figure'>OPTIONS page for HelloWorld sample resource</h5> -<p class='bpcode w800'> - http://localhost:10000/helloWorld/?method=OPTIONS +<p> + As described previously, the <code>PetStore</code> example provides an example of auto-generated Swagger JSON: </p> -<img class='bordered w800' src='doc-files/juneau-rest-server.OptionsPages.1.png'> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.1.png'> <p> - The {@link oajr.BasicRestServlet} class implements the page by creating a method - mapped to the <l>OPTIONS</l> HTTP method that simply returns a Swagger bean: + Using {@link oaj.dto.swagger.ui.SwaggerUI}, we're able to render that JSON as a Swagger user interface: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.2.png'> +<p> + Any subclass of {@link oajr.BasicRestServlet} gets an auto-generated Swagger UI when performing an <code>OPTIONS</code> + request with <code>Accept: text/html</code>. +</p> +<p> + The underlying mechanics are simple. + The {@link oajr.BasicRestServlet#getOptions(RestRequest)} method returns a {@link oaj.dto.swagger.Swagger} bean + consisting of information gathered from annotations and other sources. + Then that bean is swapped for a {@link oaj.dto.swagger.ui.SwaggerUI} bean when rendered as HTML. +</p> +<p> + Here's the class that defines the behavior: </p> <p class='bpcode w800'> - <ja>@RestResource</ja>(...) - <jk>public class</jk> BasicRestServlet <jk>extends</jk> RestServlet { - - <ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>, - summary=<js>"Resource options"</js>, + <ja>@RestResource</ja>( + + <jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter.</jc> + allowedMethodParams=<js>"OPTIONS"</js>, + + ... + ) + <jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig { + + <jd>/** + * [OPTIONS /*] - Show resource options. + * + * <ja>@param</ja> req The HTTP request. + * <ja>@return</ja> A bean containing the contents for the OPTIONS page. + */</jd> + <ja>@RestMethod</ja>(name=OPTIONS, path=<js>"/*"</js>, + summary=<js>"Swagger documentation"</js>, + description=<js>"Swagger documentation for this resource."</js>, htmldoc=<ja>@HtmlDoc</ja>( + <jc>// Override the nav links for the swagger page.</jc> navlinks={ - <js>"back: servlet:/,"</js>, - <js>"json: servlet:/?method=OPTIONS&Accept=text/json&plainText=true"</js> - } + <js>"back: servlet:/"</js>, + <js>"json: servlet:/?method=OPTIONS&Accept=text/json&plainText=true"</js> + }, + <jc>// Never show aside contents of page inherited from class.</jc> + aside=<js>"NONE"</js> ) + + <jc>// POJO swaps to apply to all serializers/parsers.</jc> + pojoSwaps={ + <jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc> + <jc>// This is a per-media-type swap that only applies to text/html requests.</jc> + SwaggerUI.<jk>class</jk> + }, + + <jc>// Properties to apply to all serializers/parsers and REST-specific API objects.</jc> + properties={ + <jc>// Add descriptions to the following types when not specified:</jc> + <ja>@Property</ja>(name=<jsf>JSONSCHEMA_addDescriptionsTo</jsf>, value=<js>"bean,collection,array,map,enum"</js>), + + <jc>// Add x-example to the following types:</jc> + <ja>@Property</ja>(name=<jsf>JSONSCHEMA_addExamplesTo</jsf>, value=<js>"bean,collection,array,map"</js>), + + <jc>// Don't generate schema information on the Swagger bean itself or HTML beans.</jc> + <ja>@Property</ja>(name=<jsf>INFOPROVIDER_ignoreTypes</jsf>, value=<js>"Swagger,org.apache.juneau.dto.html5.*"</js>) + }, + + <jc>// Shortcut for boolean properties.</jc> + flags={ + <jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc> + <jsf>JSONSCHEMA_useBeanDefs</jsf> + } ) <jk>public</jk> Swagger getOptions(RestRequest req) { + <jc>// Localized Swagger for this resource is available through the RestRequest object.</jc> <jk>return</jk> req.getSwagger(); } } </p> <p> - This page is constructed using the Info Provider API described next. + Let's look at the various parts of the <code>Petstore</code> application Swagger UI to see how they are defined. +</p> + +<h5 class='topic'>General Information</h5> +<p> + The top part of the page shows general information about the REST interface: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.3.png'> +<p> + The information is pulled from the {@link oajr.annotation.RestResource#swagger() @RestResource(swagger)} annotation. +</p> +<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=@ResourceSwagger(<js>"$F{PetStoreResource.json}"</js>), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + In this particular case, the Swagger is pulled in from a localized Swagger JSON file located in the + <code>org.apache.juneau.examples.rest.petstore</code> package using the {@link oajr.vars.FileVar $F} variable. +</p> +<h5 class='figure'>PetStoreResource.json</h5> +<p class='bpcode w800'> + { + <jok>"swagger"</jok>: <jov>"2.0"</jov>, + <jok>"info"</jok>: { + <jok>"version"</jok>: <jov>"1.0.0"</jov>, + <jok>"title"</jok>: <jov>"Swagger Petstore"</jov>, + <jok>"termsOfService"</jok>: <jov>"You are on your own."</jov>, + <jok>"contact"</jok>: { + <jok>"name"</jok>: <jov>"Juneau Development Team"</jov>, + <jok>"email"</jok>: <jov>"d...@juneau.apache.org"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + }, + <jok>"license"</jok>: { + <jok>"name"</jok>: <jov>"Apache 2.0"</jov>, + <jok>"url"</jok>: <jov>"http://www.apache.org/licenses/LICENSE-2.0.html"</jov> + } + }, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more about Juneau"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + }, + ... + } +</p> +<p> + Note that the {@link oajr.vars.FileVar $F} variable allows for request-locale-sensitive name matching so that you can provide + localized Swagger information. +</p> +<p> + The {@link oajr.vars.FileVar $F} variable simply expands to a string to fill the {@link oajr.annotation.ResourceSwagger#value() @ResourceSwagger(value)} + annotation. + You could equivalently embed JSON directly into your annotation like so: +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + <js>"{"</js>, + <js>"swagger: '2.0',"</js>, + <js>"version: '1.0.0',",</js>, + ... + <js>"}"</js> + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + However, a more typical scenario is to define all of your Swagger as annotations: +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + version=<js>"1.0.0"</js>, + title=<js>"Swagger Petstore"</js>, + termsOfService=<js>"You are on your own."</js>, + contact=<ja>@Contact</ja>( + name=<js>"Juneau Development Team"</js>, + email=<js>"d...@juneau.apache.org"</js>, + url=<js>"http://juneau.apache.org"</js> + ), + license=<ja>@License</ja>( + name=<js>"Apache 2.0"</js>, + url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js> + ), + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more about Juneau"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + All annotations support {@doc DefaultRestSvlVariables SVL variables}, so you could for example + pull localized strings from resource bundles using {@link oajr.vars.LocalizationVar $L} variables. +</p> +<p class='bpcode w800'> + <ja>@RestResource</ja>( + path=<js>"/petstore"</js>, + title=<js>"Petstore application"</js>, + messages=<js>"nls/MyMessages"</js>, + ... + swagger=<ja>@ResourceSwagger</ja>( + version=<js>"1.0.0"</js>, + title=<js>"$L{myTitle}"</js>, + termsOfService=<js>"$L{myTermsOfService}"</js>, + contact=<ja>@Contact</ja>( + name=<js>"$L{myTeam}"</js>, + email=<js>"d...@juneau.apache.org"</js>, + url=<js>"http://juneau.apache.org"</js> + ), + license=<ja>@License</ja>( + name=<js>"Apache 2.0"</js>, + url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js> + ), + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"$L{myExternalDocsDescription}"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + ... + ) + <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...} +</p> +<p> + A third option is to define your Swagger information in your {@link oajr.annotation.RestResource#messages @RestResource(messages)} resource + bundle using predefined Swagger keywords: +</p> +<p class='bpcode w800'> + <mk>PetStoreResource.version</mk> = <mv>1.0.0</mv> + <mk>PetStoreResource.title</mk> = <mv>Swagger Petstore</mv> + <mk>PetStoreResource.termsOfService</mk> = <mv>You are on your own.</mv> + <mk>PetStoreResource.contact</mk> = <mv>{name:'Juneau Development Team', email:'d...@juneau.apache.org',...}</mv> + <mk>PetStoreResource.license</mk> = <mv>{name:'Apache 2.0',...}</mv> + <mk>PetStoreResource.externalDocs</mk> = <mv>{description:'Find out more about Juneau',...}</mv> +</p> +<p> + Information defined in multiple locations are merged into a single set of data. + When the same information is provided in multiple locations, the following order-of-precedence is used: +</p> +<ol> + <li>Java annotations + <li>Resource bundle + <li>Swagger JSON file +</ol> + +<h5 class='topic'>Tags</h5> +<p> + Tags allow you to group operations into general categories. + In the user interface, these can be expanded/collapsed by clicking on the tag sections. + <br>In the example below, the <code>pet</code> and <code>store</code> tag sections are collapsed + and the <code>user</code> section is not: +</p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.4.png'> +<p> + Tags are also defined in the <ja>@ResourceSwagger</ja> annotation +</p> +<h5 class='figure'>PetStoreResource.json</h5> +<p class='bpcode w800'> + <jok>"tags"</jok>: [ + { + <jok>"name"</jok>: <jov>"pet"</jov>, + <jok>"description"</jok>: <jov>"Everything about your Pets"</jov>, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + } + }, + { + <jok>"name"</jok>: <jov>"store"</jov>, + <jok>"description"</jok>: <jov>"Access to Petstore orders"</jov> + }, + { + <jok>"name"</jok>: <jov>"user", + <jok>"description"</jok>: <jov>"Operations about user"</jov>, + <jok>"externalDocs"</jok>: { + <jok>"description"</jok>: <jov>"Find out more about our store"</jov>, + <jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov> + } + } + ], + +</p> +<p> + The annotation-only approach is shown here: +</p> +<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5> +<p class='bpcode w800'> + swagger=<ja>@ResourceSwagger</ja>( + ... + tags={ + <ja>@Tag</ja>( + name=<js>"pet"</js>, + description=<js>"Everything about your Pets"</js>, + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ), + <ja>@Tag</ja>( + name=<js>"store"</js>, + description=<js>"Access to Petstore orders"</js> + ), + <ja>@Tag</ja>( + name=<js>"user"</js>, + description=<js>"Operations about user"</js>, + externalDocs=<ja>@ExternalDocs</ja>( + description=<js>"Find out more about our store"</js>, + url=<js>"http://juneau.apache.org"</js> + ) + ) + } + ), +</p> +<p> + Tags are associated with operations using the {@link oajr.annotation.MethodSwagger#tags() @MethodSwagger(tags)} annotation: +</p> + +<h5 class='figure'>GET /user operation</h5> +<p class='bpcode w800'> + <ja>@RestMethod</ja>( + name=<jsf>GET</jsf>, + path=<js>"/user"</js>, + summary=<js>"Petstore users"</js>, + swagger=<ja>@MethodSwagger</ja>( + tags=<js>"user"</js> + ) + ) + <jk>public</jk> Collection<User> getUsers() <jk>throws</jk> NotAcceptable {...} +</p> +<p> + Operations can be mapped to multiple tags. +</p> +<p> + Tags are optional. + Operations not mapped to tags are listed in the UI before tagged operations. +</p> +<p> + For example, the <code>getTopPage()</code> method in <code>PetStoreResource</code> is not tagged, + as well as the <code>getOptions()</code> method inherited from <code>BaseRestServlet</code>, so these + show up at the top of the page: </p> +<img class='bordered' style='width:900px' src='doc-files/juneau-rest-server.Swagger.5.png'> + \ No newline at end of file diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.1.png b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.1.png new file mode 100644 index 0000000..69b656f Binary files /dev/null and b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.1.png differ diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.2.png b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.2.png new file mode 100644 index 0000000..284fa85 Binary files /dev/null and b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.2.png differ diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.3.png b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.3.png new file mode 100644 index 0000000..c642c41 Binary files /dev/null and b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.3.png differ diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.4.png b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.4.png new file mode 100644 index 0000000..42762e0 Binary files /dev/null and b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.4.png differ diff --git a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.5.png b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.5.png new file mode 100644 index 0000000..d889fa7 Binary files /dev/null and b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/doc-files/juneau-rest-server.Swagger.5.png differ diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java index 83d3087..e0c3a67 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java @@ -28,7 +28,7 @@ public class Pet { private Species species; private String name; private List<String> photoUrls; - private List<Tag> tags; + private List<PetTag> tags; private PetStatus status; // This shows an example generated from a static method. @@ -38,7 +38,7 @@ public class Pet { .id(123) .species(Species.example()) .name("Doggie") - .tags(Tag.example()) + .tags(PetTag.example()) .status(PetStatus.AVAILABLE); } @@ -81,16 +81,16 @@ public class Pet { return this; } - public List<Tag> getTags() { + public List<PetTag> getTags() { return tags; } - public Pet tags(List<Tag> tags) { + public Pet tags(List<PetTag> tags) { this.tags = tags; return this; } - public Pet tags(Tag...tags) { + public Pet tags(PetTag...tags) { this.tags = Arrays.asList(tags); return this; } @@ -113,7 +113,7 @@ public class Pet { public boolean hasTag(String...tags) { for (String tag : tags) - for (Tag t : this.tags) + for (PetTag t : this.tags) if (t.getName().equals(tag)) return true; return false; diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java index 3b89175..b9a4208 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java @@ -30,7 +30,7 @@ public class PetStore { IdMap<Long,Pet> petDb = IdMap.createLongMap(Pet.class); IdMap<Long,Species> speciesDb = IdMap.createLongMap(Species.class); IdMap<Long,Order> orderDb = IdMap.createLongMap(Order.class); - IdMap<Long,Tag> tagDb = IdMap.createLongMap(Tag.class); + IdMap<Long,PetTag> tagDb = IdMap.createLongMap(PetTag.class); ConcurrentHashMap<String,User> userDb = new ConcurrentHashMap<>(); public PetStore init() throws Exception { @@ -42,7 +42,7 @@ public class PetStore { // Note that these must be loaded in the specified order to prevent IdNotFound exceptions. for (Species s : parser.parse(getStream("Species.json"), Species[].class)) add(s); - for (Tag t : parser.parse(getStream("Tags.json"), Tag[].class)) + for (PetTag t : parser.parse(getStream("Tags.json"), PetTag[].class)) add(t); parser = parser.builder().pojoSwaps(new CategorySwap(), new TagSwap()).build(); @@ -91,15 +91,15 @@ public class PetStore { return value; } - public Tag getTag(long id) throws IdNotFound { - Tag value = tagDb.get(id); + public PetTag getTag(long id) throws IdNotFound { + PetTag value = tagDb.get(id); if (value == null) throw new IdNotFound(id, Pet.class); return value; } - public Tag getTag(String name) throws InvalidTag { - for (Tag value : tagDb.values()) + public PetTag getTag(String name) throws InvalidTag { + for (PetTag value : tagDb.values()) if (value.getName().equals(name)) return value; throw new InvalidTag(); @@ -132,7 +132,7 @@ public class PetStore { return orderDb.values(); } - public Collection<Tag> getTags() { + public Collection<PetTag> getTags() { return tagDb.values(); } @@ -169,12 +169,12 @@ public class PetStore { return value; } - public Tag add(Tag value) throws IdConflict { + public PetTag add(PetTag value) throws IdConflict { if (value.getId() == 0) value.id(tagDb.nextId()); - Tag old = tagDb.putIfAbsent(value.getId(), value); + PetTag old = tagDb.putIfAbsent(value.getId(), value); if (old != null) - throw new IdConflict(value.getId(), Tag.class); + throw new IdConflict(value.getId(), PetTag.class); return value; } @@ -221,20 +221,20 @@ public class PetStore { return add(o); } - private Tag[] getTags(String[] tags) { + private PetTag[] getTags(String[] tags) { if (tags == null) return null; - Tag[] l = new Tag[tags.length]; + PetTag[] l = new PetTag[tags.length]; for (int i = 0; i < tags.length; i++) l[i]= getOrCreateTag(tags[i]); return l; } - private Tag getOrCreateTag(String name) { - for (Tag t : tagDb.values()) + private PetTag getOrCreateTag(String name) { + for (PetTag t : tagDb.values()) if (t.getName().equals(name)) return t; - return add(new Tag().name(name)); + return add(new PetTag().name(name)); } public Order update(Order value) throws IdNotFound { @@ -244,11 +244,11 @@ public class PetStore { return value; } - public Tag update(Tag value) throws IdNotFound, InvalidTag { + public PetTag update(PetTag value) throws IdNotFound, InvalidTag { assertValidTag(value.getName()); - Tag old = tagDb.replace(value.getId(), value); + PetTag old = tagDb.replace(value.getId(), value); if (old == null) - throw new IdNotFound(value.getId(), Tag.class); + throw new IdNotFound(value.getId(), PetTag.class); return value; } @@ -335,13 +335,13 @@ public class PetStore { } } - public class TagSwap extends PojoSwap<Tag,String> { + public class TagSwap extends PojoSwap<PetTag,String> { @Override - public String swap(BeanSession bs, Tag o) throws Exception { + public String swap(BeanSession bs, PetTag o) throws Exception { return o.getName(); } @Override - public Tag unswap(BeanSession bs, String o, ClassMeta<?> hint) throws Exception { + public PetTag unswap(BeanSession bs, String o, ClassMeta<?> hint) throws Exception { return getTag(o); } } 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 4989647..6d5e7c0 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 @@ -79,7 +79,46 @@ import org.apache.juneau.rest.converters.*; // Resolve recursive references when showing schema info in the swagger. @Property(name=SWAGGERUI_resolveRefsMaxDepth, value="99") }, - swagger=@ResourceSwagger("$F{PetStoreResource.json}"), + swagger=@ResourceSwagger( + version="1.0.0", + title="Swagger Petstore", + termsOfService="You are on your own.", + contact=@Contact( + name="Juneau Development Team", + email="d...@juneau.apache.org", + url="http://juneau.apache.org" + ), + license=@License( + name="Apache 2.0", + url="http://www.apache.org/licenses/LICENSE-2.0.html" + ), + externalDocs=@ExternalDocs( + description="Find out more about Juneau", + url="http://juneau.apache.org" + ), + tags={ + @Tag( + name="pet", + description="Everything about your Pets", + externalDocs=@ExternalDocs( + description="Find out more", + url="http://juneau.apache.org" + ) + ), + @Tag( + name="store", + description="Access to Petstore orders" + ), + @Tag( + name="user", + description="Operations about user", + externalDocs=@ExternalDocs( + description="Find out more about our store", + url="http://juneau.apache.org" + ) + ) + } + ), staticFiles={"htdocs:htdocs"} ) public class PetStoreResource extends BasicRestServletJena { @@ -248,7 +287,7 @@ public class PetStoreResource extends BasicRestServletJena { ), tr( th("Tags:"), - td(input().name("tags").type("text").value(Tag.asString(pet.getTags()))), + td(input().name("tags").type("text").value(PetTag.asString(pet.getTags()))), td(new Tooltip("(?)", "Arbitrary textual tags (comma-delimited).", br(), "e.g. 'fluffy,friendly'")) ), tr( diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Tag.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java similarity index 85% rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Tag.java rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java index f57f3a8..1257f3d 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Tag.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java @@ -21,8 +21,8 @@ import org.apache.juneau.internal.*; import org.apache.juneau.transform.*; @Bean(typeName="Tag", fluentSetters=true) -@Swap(Tag.TagNameOnly.class) -public class Tag { +@Swap(PetTag.TagNameOnly.class) +public class PetTag { private long id; private String name; @@ -30,7 +30,7 @@ public class Tag { return id; } - public Tag id(long id) { + public PetTag id(long id) { this.id = id; return this; } @@ -39,21 +39,21 @@ public class Tag { return name; } - public Tag name(String name) { + public PetTag name(String name) { this.name = name; return this; } @Example - public static Tag example() { - return new Tag() + public static PetTag example() { + return new PetTag() .id(123) .name("MyTag"); } - public static class TagNameOnly extends PojoSwap<Tag,String> { + public static class TagNameOnly extends PojoSwap<PetTag,String> { @Override - public String swap(BeanSession bs, Tag o) throws Exception { + public String swap(BeanSession bs, PetTag o) throws Exception { return o.getName(); } @Override @@ -62,11 +62,11 @@ public class Tag { } } - public static String asString(List<Tag> tags) { + public static String asString(List<PetTag> tags) { if (tags == null) return ""; List<String> l = new ArrayList<>(tags.size()); - for (Tag t : tags) + for (PetTag t : tags) l.add(t.getName()); return StringUtils.join(l, ','); } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServlet.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServlet.java index 95b1487..dc3c469 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServlet.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServlet.java @@ -177,31 +177,7 @@ import org.apache.juneau.xmlschema.*; "up: request:/..", "options: servlet:/?method=OPTIONS" } - ), - - // POJO swaps to apply to all serializers/parsers. - pojoSwaps={ - // Use the SwaggerUI swap when rendering Swagger beans. - SwaggerUI.class - }, - - // Properties to apply to all serializers/parsers and REST-specific API objects. - properties={ - // Add descriptions to the following types when not specified: - @Property(name=JSONSCHEMA_addDescriptionsTo, value="bean,collection,array,map,enum"), - - // Add x-example to the following types: - @Property(name=JSONSCHEMA_addExamplesTo, value="bean,collection,array,map"), - - // Don't generate schema information on the Swagger bean itself or HTML beans. - @Property(name=INFOPROVIDER_ignoreTypes, value="Swagger,org.apache.juneau.dto.html5.*") - }, - - // Shortcut for boolean properties. - flags={ - // Use $ref references for bean definitions to reduce duplication in Swagger. - JSONSCHEMA_useBeanDefs - } + ) ) public abstract class BasicRestServlet extends RestServlet implements BasicRestConfig { private static final long serialVersionUID = 1L; @@ -215,6 +191,7 @@ public abstract class BasicRestServlet extends RestServlet implements BasicRestC @RestMethod(name=OPTIONS, path="/*", summary="Swagger documentation", description="Swagger documentation for this resource.", + htmldoc=@HtmlDoc( // Override the nav links for the swagger page. navlinks={ @@ -223,7 +200,32 @@ public abstract class BasicRestServlet extends RestServlet implements BasicRestC }, // Never show aside contents of page inherited from class. aside="NONE" - ) + ), + + // POJO swaps to apply to all serializers/parsers on this method. + pojoSwaps={ + // Use the SwaggerUI swap when rendering Swagger beans. + // This is a per-media-type swap that only applies to text/html requests. + SwaggerUI.class + }, + + // Properties to apply to all serializers/parsers and REST-specific API objects on this method. + properties={ + // Add descriptions to the following types when not specified: + @Property(name=JSONSCHEMA_addDescriptionsTo, value="bean,collection,array,map,enum"), + + // Add x-example to the following types: + @Property(name=JSONSCHEMA_addExamplesTo, value="bean,collection,array,map"), + + // Don't generate schema information on the Swagger bean itself or HTML beans. + @Property(name=INFOPROVIDER_ignoreTypes, value="Swagger,org.apache.juneau.dto.html5.*") + }, + + // Shortcut for boolean properties. + flags={ + // Use $ref references for bean definitions to reduce duplication in Swagger. + JSONSCHEMA_useBeanDefs + } ) public Swagger getOptions(RestRequest req) { // Localized Swagger for this resource is available through the RestRequest object. diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java index ac65c08..4d49b96 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java @@ -41,7 +41,6 @@ import org.apache.juneau.httppart.*; import org.apache.juneau.httppart.bean.*; import org.apache.juneau.internal.*; import org.apache.juneau.json.*; -import org.apache.juneau.jsonschema.*; import org.apache.juneau.msgpack.*; import org.apache.juneau.oapi.*; import org.apache.juneau.parser.*; @@ -2989,7 +2988,6 @@ public final class RestContext extends BeanContext { private final ParserGroup parsers; private final HttpPartSerializer partSerializer; private final HttpPartParser partParser; - private final JsonSchemaGenerator jsonSchemaGenerator; private final EncoderGroup encoders; private final List<MediaType> consumes, @@ -3152,7 +3150,6 @@ public final class RestContext extends BeanContext { parsers = ParserGroup.create().append(getInstanceArrayProperty(REST_parsers, Parser.class, new Parser[0], true, resource, ps)).build(); partSerializer = getInstanceProperty(REST_partSerializer, HttpPartSerializer.class, OpenApiSerializer.class, true, resource, ps); partParser = getInstanceProperty(REST_partParser, HttpPartParser.class, OpenApiParser.class, true, resource, ps); - jsonSchemaGenerator = new JsonSchemaGenerator(ps); encoders = new EncoderGroupBuilder().append(getInstanceArrayProperty(REST_encoders, Encoder.class, new Encoder[0], true, resource, ps)).build(); beanContext = BeanContext.create().apply(ps).build(); @@ -4247,17 +4244,6 @@ public final class RestContext extends BeanContext { } /** - * Returns the JSON-Schema serializer associated with this resource. - * - * @return - * The JSON-Schema serializer associated with this resource. - * <br>Never <jk>null</jk>. - */ - public JsonSchemaGenerator getJsonSchemaGenerator() { - return jsonSchemaGenerator; - } - - /** * Returns the HTTP-part serializer associated with this resource. * * <h5 class='section'>See Also:</h5> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java index 034dd05..c496a84 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java @@ -60,6 +60,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> { private final Integer priority; private final RestContext context; final java.lang.reflect.Method method; + final PropertyStore propertyStore; final SerializerGroup serializers; final ParserGroup parsers; final EncoderGroup encoders; @@ -100,6 +101,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> { this.partSerializer = b.partSerializer; this.beanContext = b.beanContext; this.properties = b.properties; + this.propertyStore = b.propertyStore; this.defaultRequestHeaders = b.defaultRequestHeaders; this.defaultQuery = b.defaultQuery; this.defaultFormData = b.defaultFormData; @@ -126,6 +128,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> { HttpPartSerializer partSerializer; BeanContext beanContext; RestMethodProperties properties; + PropertyStore propertyStore; Map<String,Object> defaultRequestHeaders, defaultQuery, defaultFormData; long maxInput; Integer priority; @@ -229,15 +232,15 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> { this.requiredMatchers = requiredMatchers.toArray(new RestMatcher[requiredMatchers.size()]); this.optionalMatchers = optionalMatchers.toArray(new RestMatcher[optionalMatchers.size()]); - PropertyStore ps = context.getPropertyStore(); - ps = ps.builder().set(BEAN_beanFilters, mBeanFilters).set(BEAN_pojoSwaps, mPojoSwaps).build(); + PropertyStoreBuilder psb = context.getPropertyStore().builder().set(BEAN_beanFilters, mBeanFilters).set(BEAN_pojoSwaps, mPojoSwaps); + for (Property p1 : m.properties()) + psb.set(p1.name(), p1.value()); + for (String p1 : m.flags()) + psb.set(p1, true); + this.propertyStore = psb.build(); if (sgb != null) { - sgb.apply(ps); - for (Property p1 : m.properties()) - sgb.set(p1.name(), p1.value()); - for (String p1 : m.flags()) - sgb.set(p1, true); + sgb.apply(propertyStore); if (m.bpi().length > 0) { Map<String,String> bpiMap = new LinkedHashMap<>(); for (String s : m.bpi()) { @@ -269,32 +272,19 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> { } if (pgb != null) { - pgb.apply(ps); - for (Property p1 : m.properties()) - pgb.set(p1.name(), p1.value()); - for (String p1 : m.flags()) - pgb.set(p1, true); + pgb.apply(propertyStore); pgb.beanFilters(mBeanFilters); pgb.pojoSwaps(mPojoSwaps); } if (uepb != null) { - uepb.apply(ps); - for (Property p1 : m.properties()) - uepb.set(p1.name(), p1.value()); - for (String p1 : m.flags()) - uepb.set(p1, true); + uepb.apply(propertyStore); uepb.beanFilters(mBeanFilters); uepb.pojoSwaps(mPojoSwaps); } if (bcb != null) { - bcb.apply(ps); - for (Property p1 : m.properties()) - bcb.set(p1.name(), p1.value()); - for (String p1 : m.flags()) - bcb.set(p1, true); - bcb.beanFilters(mBeanFilters); + bcb.apply(propertyStore); bcb.pojoSwaps(mPojoSwaps); } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java index 5b90772..da5b25a 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java @@ -384,6 +384,20 @@ public final class RestRequest extends HttpServletRequestWrapper { } /** + * Returns the {@link PropertyStore} for this request. + * + * <p> + * Consists of a read-only roll-up of all configuration properties defined on this method and class. + * + * @return + * The property store for this request. + * <br>Never <jk>null</jk>. + */ + public PropertyStore getPropertyStore() { + return restJavaMethod == null ? PropertyStore.DEFAULT : restJavaMethod.propertyStore; + } + + /** * Sets the charset to expect on the request body. */ @Override /* ServletRequest */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java index 5c750cc..5d54201 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java @@ -79,7 +79,7 @@ final class SwaggerGenerator { this.ignoreTypes = ignoreTypes; this.locale = req.getLocale(); this.context = req.getContext(); - this.js = context.getJsonSchemaGenerator().createSession(); + this.js = new JsonSchemaGenerator(req.getPropertyStore()).createSession(); this.c = context.getResource().getClass(); this.resource = context.getResource(); this.mb = context.getMessages();