Author: buildbot
Date: Sun Jan 9 23:28:30 2022
New Revision: 1077941
Log:
Production update by buildbot for tapestry
Added:
websites/production/tapestry/content/rest-support-580page-is-work-in-progress.html
Modified:
websites/production/tapestry/content/cache/main.pageCache
Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.
Added:
websites/production/tapestry/content/rest-support-580page-is-work-in-progress.html
==============================================================================
---
websites/production/tapestry/content/rest-support-580page-is-work-in-progress.html
(added)
+++
websites/production/tapestry/content/rest-support-580page-is-work-in-progress.html
Sun Jan 9 23:28:30 2022
@@ -0,0 +1,223 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="keywords" content="tapestry, apache, apache tapestry, framework,
java, web, component, open source, application, dynamic, scalable, robust,
servlet">
+ <meta name="description" content="Apache Tapestry is a open-source
component-oriented framework for creating dynamic, robust, highly scalable web
applications in Java. Tapestry complements and builds upon the standard Java
Servlet API, and so it works in any servlet container or application server.">
+
+ <title>
+ REST Support (5.8.0+)(page is work in progress) - Apache Tapestry
+ </title>
+
+ <link rel="apple-touch-icon-precomposed" sizes="144x144"
href="/images/apache-tapestry-icon-144.png">
+ <link rel="apple-touch-icon-precomposed" sizes="114x114"
href="/images/apache-tapestry-icon-114.png">
+ <link rel="apple-touch-icon-precomposed" sizes="72x72"
href="/images/apache-tapestry-icon-72.png">
+ <link rel="apple-touch-icon-precomposed"
href="/images/apache-tapestry-icon-57.png">
+ <link rel="shortcut icon" href="/images/apache-tapestry-icon-32.png">
+
+ <link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Sarabun:ital,wght@0,400;0,700;1,400;1,700&display=swap">
+ <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous">
+ <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
+ <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism.min.css">
+ <link rel="stylesheet" href="/styles/main.css">
+
+ <script type="text/javascript">
+ if (window.location.protocol === 'http:' && window.location.hostname !==
'localhost') {
+ window.location = window.location.href.replace('http://', 'https://');
+ }
+ </script>
+
+ <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous" defer></script>
+ <script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous" defer></script>
+ <script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous" defer></script>
+ <script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/prism.min.js"
defer></script>
+ <script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"
defer></script>
+
+ <script type="text/javascript">
+ window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new
Date;
+ ga('create', 'UA-400821-1', 'auto');
+ ga('send', 'pageview');
+ </script>
+ <script async src="https://www.google-analytics.com/analytics.js"></script>
+</head>
+<body>
+ <!-- /// Navigation Start -->
+ <div id="navigation"><p><img class="wysiwyg-unknown-macro"
src="https://cwiki.apache.org/confluence/plugins/servlet/confluence/placeholder/unknown-macro?name=html&locale=en_GB&version=2"></p></div>
+ <!-- /// Navigation End -->
+
+ <article>
+ <div class="container-fluid">
+ <div class="container pt-5">
+ <div class="row">
+ <div class="col-12">
+ <!-- /// Breadcrumb Start -->
+ <div id="breadcrumb" class="mb-2 text-small">
+ <a href="index.html">Apache
Tapestry</a> > <a
href="documentation.html">Documentation</a> > <a
href="user-guide.html">User Guide</a> > <a
href="rest-support-580page-is-work-in-progress.html">REST Support (5.8.0+)(page
is work in progress)</a>
+ </div>
+ <!-- /// Breadcrumb End -->
+
+ <!-- /// Smallbanner Start -->
+ <div id="smallbanner"><img
class="wysiwyg-unknown-macro"
src="https://cwiki.apache.org/confluence/plugins/servlet/confluence/placeholder/unknown-macro?name=html&locale=en_GB&version=2"></div>
+ <!-- /// Smallbanner Start -->
+
+ <!-- /// Content Start -->
+ <div id="content">
+ <div id="ConfluenceContent"><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-/*<![CDATA[*/div.rbtoc1641770530954{padding:0px;}div.rbtoc1641770530954ul{list-style:disc;margin-left:0px;}div.rbtoc1641770530954li{margin-left:0px;padding-left:0px;}/*]]>*/#RESTSupport(5.8.0+)(pageisworkinprogres"><style
type="text/css">/*<![CDATA[*/
+div.rbtoc1641770530954 {padding: 0px;}
+div.rbtoc1641770530954 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1641770530954 li {margin-left: 0px;padding-left: 0px;}
+
+/*]]>*/</style></h2><div class="toc-macro rbtoc1641770530954">
+<ul class="toc-indentation"><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-"></a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Overview">Overview</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-WritingRESTendpoints">Writing
REST endpoints</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Readingtherequestbodywith@RequestBody">Reading
the request body with @RequestBody</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-AnsweringRESTrequests">Answering
REST requests</a>
+<ul class="toc-indentation"><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Contentresponses">Content
responses</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Non-contentresponses">Non-content
responses</a></li></ul>
+</li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-MappedEntityManagerservice">MappedEntityManager
service</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-IntegrationwithJacksonDatabindwithtapestry-rest-jackson">Integration
with Jackson Databind with tapestry-rest-jackson</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-AutomaticgenerationofOpenAPI3.0(Swagger)descriptions">Automatic
generation of OpenAPI 3.0 (Swagger) descriptions</a>
+<ul class="toc-indentation"><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Customizingnames,summariesanddescriptionsusingmessagesandconfigurationsymbols">Customizing
names, summaries and descriptions using messages and configuration
symbols</a></li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-Furthercustomizations">Further
customizations</a></li></ul>
+</li><li><a
href="#RESTSupport(5.8.0+)(pageisworkinprogress)-tapestry-openapi-viewer">tapestry-openapi-viewer</a></li></ul>
+</div><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-Overview">Overview</h2><p>Since
version 5.8.0, Tapestry provides out-of-the-box support for writing REST
endpoints as regular event handler methods in page classes. They work in the
same way the <code>activate</code> event (i.e. <code>onActivate()</code>
methods) work, including how event handler method parameters work. The
<code>@RequestBody</code> annotation was created so event handler methods can
access the request body. The @StaticActivationContextValue annotation was
created so you can write event handler methods that are only called when one or
more parts of the URL path match given values. Both annotations are not
REST-specific and can be used in any event handler method. A new
subproject/JAR, tapestry-rest-jackson, automates the use of Jackson Databind to
make JSON conversions. tapestry-Swagger/OpenAPI 3.0 descriptions are generated
automatically and can be easily customized. A new subproject/JAR,
tapestry-openapi-view
er, provides an out-of-the-box viewer for the generated OpenAPI description
using Swagger UI. For a Tapestry REST support example project, check out <a
class="external-link" href="https://github.com/thiagohp/tapestry-rest-example"
rel="nofollow">https://github.com/thiagohp/tapestry-rest-example</a>.</p><p>Some
important warnings:</p><ol><li>Tapestry's REST support isn't an implementation
of JAX-RS, so they expect any of its concepts to work here. It's REST
implemented in a Tapestry way.</li><li><span style="letter-spacing:
0.0px;">REST endpoint event handler methods in components are ignored just like
<code>onActivate()</code> is.</span></li></ol><p>The following HTTP methods are
supported:</p><div class="table-wrap"><table class="table table-bordered
table-responsive"><colgroup span="1"><col span="1" style="width:
21.3382%;"><col span="1" style="width: 30.9222%;"><col span="1" style="width:
25.859%;"><col span="1" style="width: 21.8807%;"></colgroup><tbody><tr><th
colspan="1" rowsp
an="1" class="confluenceTh">HTTP method</th><th colspan="1" rowspan="1"
class="confluenceTh">Tapestry event name</th><th colspan="1" rowspan="1"
class="confluenceTh"><p>EventConstants</p><p>constant name</p></th><th
colspan="1" rowspan="1" class="confluenceTh"><p>Event handler</p><p>method
name</p></th></tr><tr><td colspan="1" rowspan="1"
class="confluenceTd"><code>GET</code></td><td colspan="1" rowspan="1"
class="confluenceTd"><code>httpGet</code></td><td colspan="1" rowspan="1"
class="confluenceTd"><code>HTTP_GET</code></td><td colspan="1" rowspan="1"
class="confluenceTd"><code>onHttpGet</code></td></tr><tr><td colspan="1"
rowspan="1" class="confluenceTd"><code>POST</code></td><td colspan="1"
rowspan="1" class="confluenceTd"><code>httpPost</code></td><td colspan="1"
rowspan="1" class="confluenceTd"><code>HTTP_POST</code></td><td colspan="1"
rowspan="1" class="confluenceTd"><code>onHttpPost</code></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><code>DELETE</code></td
><td colspan="1" rowspan="1"
>class="confluenceTd"><code>httpDelete</code></td><td colspan="1" rowspan="1"
>class="confluenceTd"><code>HTTP_DELETE</code></td><td colspan="1" rowspan="1"
>class="confluenceTd"><code>onHttpDelete</code></td></tr><tr><td colspan="1"
>rowspan="1" class="confluenceTd"><code>PUT</code></td><td colspan="1"
>rowspan="1" class="confluenceTd"><code>httpPut</code></td><td colspan="1"
>rowspan="1" class="confluenceTd"><code>HTTP_PUT</code></td><td colspan="1"
>rowspan="1" class="confluenceTd"><code>onHttpPut</code></td></tr><tr><td
>colspan="1" rowspan="1" class="confluenceTd"><code>HEAD</code></td><td
>colspan="1" rowspan="1" class="confluenceTd"><code>httpHead</code></td><td
>colspan="1" rowspan="1" class="confluenceTd"><code>HTTP_HEAD</code></td><td
>colspan="1" rowspan="1"
>class="confluenceTd"><code>onHttpHead</code></td></tr><tr><td colspan="1"
>rowspan="1" class="confluenceTd"><code>PATCH</code></td><td colspan="1"
>rowspan="1" class="confluenceTd"><code>httpPatch</cod
e></td><td colspan="1" rowspan="1"
class="confluenceTd"><code>HTTP_PATCH</code></td><td colspan="1" rowspan="1"
class="confluenceTd"><code>onHttpPatch</code></td></tr></tbody></table></div><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-WritingRESTendpoints">Writing
REST endpoints</h2><p>Writing a REST endpoint in Tapestry is exactly the same
as writing <code>onActivate()</code> method in a page class. Everything is the
same: parameter handling, returned value processing, precedence rules, class
inheritance, URLs, etc. If you know how to write <code>onActivate()</code>
methods, you already know almost everything you need how to write a REST
endpoint event handler.   There are only 2 small differences between
<code>onActivate()</code> and REST endpoint event handler
methods:</p><ol><li>REST event handler methods are invoked after the
<code>onActivate()</code>. </li><li>The event name is different, according
to the HTTP method to be handled.</li></ol><p>So, for exampl
e, if you want a REST endpoint with URL /userendpoint/[id], supposing the id
is a <code>Long</code>, handling the <code>GET</code> HTTP method, you can just
write the following page class and event handler:</p><div class="code panel
pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre><code class="language-java">public class UserEndpoint {
+
+ Object onHttpGet(Long id) {
+ (...)
+ }
+ (...)
+}</code></pre>
+</div></div><p>The example above could also be written using the
<code>@OnEvent</code> annotation and would work the same:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre><code class="language-java">public class UserEndpoint {
+
+ @OnEvent(EventConstants.HTTP_GET)
+ Object getById(Long id) { // or any other method name
+ (...)
+ }
+ (...)
+}</code></pre>
+</div></div><h2 class="auto-cursor-target"
id="RESTSupport(5.8.0+)(pageisworkinprogress)-Readingtherequestbodywith@RequestBody">Reading
the request body with <code>@RequestBody</code></h2><p>Many times, specially
with POST, PUT and PATCH requests, the data is sent through the request body.
To get this data, the event handler method needs to add a parameter with the
<code>@RequestBody</code> annotation. It has a single property,
<code>allowEmpty</code>, with <code>false</code> as its default value, which
defines whether an empty request body is empty. If not, an exception will be
thrown.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre><code class="language-java">@OnEvent(EventConstants.HTTP_PUT)
+Object save(@RequestBody User user) {
+ (...)
+}
+
+@OnEvent(EventConstants.HTTP_PUT)
+Object save(Long id, @RequestBody User user) {
+ (...)
+}</code></pre>
+</div></div><p>The following types are supported
out-of-the-box:</p><ul><li><code>String</code></li><li><code>Reader</code></li><li><code>InputStream</code></li><li><code>JSONObject</code></li><li><code>JSONArray</code></li><li>Primitive
types and their wrapper types</li></ul><p>The actual conversion logic is
implemented in the <code>HttpRequestBodyConverter</code> service, which is
defined is an ordered configuration of <code>HttpRequestBodyConverter</code>
instances. The service calls all contributed instances until one of them
returns a non-null value. If none of them returns a non-null value, it falls
back to trying to find a coercion, direct or indirect, from
<code>HttpServletRequest</code> to the desired type. </p><p>Here's one
example of implementing an new <code>HttpRequestBodyConverter</code> then the
code added to <code>AppModule</code> or any other Tapestry-IoC module class to
have it used by <code>@RequestBody</code>:</p><div class="code panel pdl"
style="border-wid
th: 1px;"><div class="codeContent panelContent pdl">
+<pre><code class="language-java">/**
+ * Converts the body of HTTP requests to {@link User} instances. It delegates
this task
+ * to {@link UserService#toObject(String)}.
+ */
+public class UserHttpRequestBodyConverter implements HttpRequestBodyConverter {
+
+ private final UserService userService;
+
+ public UserHttpRequestBodyConverter(UserService userService) {
+ super();
+ this.userService = userService;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T convert(HttpServletRequest request, Class<T>
type) {
+ T value = null;
+ // Check whether this converter handles the given type
+ if (User.class.equals(type)) {
+ // Actual conversion logic
+ try {
+ value = (T)
userService.toObject(IOUtils.toString(request.getReader()));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+        }
+ return value;
+ }
+
+}</code></pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>UserHttpRequestBodyConverter contribution</b></div><div
class="codeContent panelContent pdl">
+<pre><code class="language-java"> public static void
contributeHttpRequestBodyConverter(
+ OrderedConfiguration<HttpRequestBodyConverter>
configuration) {
+
+ configuration.addInstance("User", UserHttpRequestBodyConverter.class);
// automatic instantiation and dependency injection
+ // or configuration.add("User", new
UserHttpRequestBodyConverter(...));
+ }</code></pre>
+</div></div><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-AnsweringRESTrequests">Answering
REST requests</h2><p>Just like any other Tapestry event handler method, the
returned value defines what gets to be sent to the user agent making the
request. This logic is written in <code>ComponentEventResultProcessor</code>
implementations, usually but not necessarily one per return type/class, which
are contributed to the <code>ComponentEventResultProcessor</code> service.
These implementations can also set additional HTTP headers and set the HTTP
status code.</p><p>REST requests responses usually fall into 2 types: ones just
returning HTTP status and and headers (for example, <code>HEAD</code> and
<code>DELETE</code> requests) and ones returning that and also content (for
example, <code>GET</code>, sometimes other methods too).</p><h3
id="RESTSupport(5.8.0+)(pageisworkinprogress)-Contentresponses">Content
responses</h3><p>For content responses, Tapestry has out-of-the-box support for
<
code>StreamResponse</code> (mostly binary content), 
<code>TextStreamResponse</code> (simple text content), <code>JSONArray</code>
(since Tapestry 5.8.0) and <code>JSONObject</code> (since 5.8.0).  Here's
one example for adding support for a class, <code>User</code>, converting it to
the JSON format:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre><code class="language-java">/**
+ * Handles {@link User} instances when they're returned by event handler
methods.
+ * Heavily inspired by {@link JSONCollectionEventResultProcessor} from
Tapestry itself.
+ */
+final public class UserComponentEventResultProcessor
+ implements ComponentEventResultProcessor<User> {
+
+ private final Response response;
+
+ private final ContentType contentType;
+
+ private final UserService userService;
+
+ public UserComponentEventResultProcessor(Response response,
+ @Symbol(TapestryHttpSymbolConstants.CHARSET) String outputEncoding,
+ UserService userService) {
+ this.response = response;
+ this.userService = userService;
+ contentType = new
ContentType(InternalConstants.JSON_MIME_TYPE).withCharset(outputEncoding);
+ }
+
+ public void processResultValue(User user) throws IOException
+ {
+ PrintWriter pw = response.getPrintWriter(contentType.toString());
+ pw.write(userService.toJsonString(user));
+ pw.close();
+ // You could also set extra HTTP headers or the status code here
+ }
+}</code></pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>UserComponentEventResultProcessor contribution</b></div><div
class="codeContent panelContent pdl">
+<pre><code class="language-java"> public void
contributeComponentEventResultProcessor(
+ MappedConfiguration<Class, ComponentEventResultProcessor>
configuration) {
+ configuration.addInstance(User.class,
UserComponentEventResultProcessor.class);
+ }</code></pre>
+</div></div><h3 class="auto-cursor-target"
id="RESTSupport(5.8.0+)(pageisworkinprogress)-Non-contentresponses">Non-content
responses</h3><p>For responses without content, just HTTP status and headers,
and also for simple String responses, Tapestry 5.8.0 introduced the
<code>HttpStatus</code> class. You can create instances of it by either using
its utility static methods that match HTTP status names like <code>ok()</code>,
<code>created()</code>, <code>accepted()</code>, <code>notFound()</code>
and <code>forbidden() </code>or using one of its constructors. In both cases,
you can customize the response further by using a fluent interface with methods
for header-specific methods like <code>withLocation(url)</code> and
<code>withContentLocation(url)</code> or the generic
<code>withHttpHeader(String name, String value)</code>. Check the
<code>HttpStatus</code> JavaDoc for the full list of methods.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent pan
elContent pdl">
+<pre><code class="language-java"> @OnEvent(EventConstants.HTTP_PUT)
+ Object save(@RequestBody User user) {
+ userService.save(user);
+ return HttpStatus.created()
+ .withContentLocation("Some URL")
+ .withHttpHeader("X-Something", "X-Value");
+ }
+
+</code></pre>
+</div></div><h2 class="auto-cursor-target"
id="RESTSupport(5.8.0+)(pageisworkinprogress)-MappedEntityManagerservice"><code>MappedEntityManager</code>
service</h2><p>This is a service which provides a list of mapped entities.
They're usually classes which are mapped to other formats like JSON and XML and
used to represent data received or sent to or from external processes, for
example REST endpoints. Contributions are done by package and all classes
inside the contributed ones are considered mapped entities.</p><p>This service
is used by Tapestry code, including the OpenAPI description generator and
tapestry-rest-jackson, to know which classes should be considered part of the
webapp's external APIs.</p><p>Here's an example contribution:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+<pre><code class="language-java"> public static void
contributeMappedEntityManager(Configuration<String> configuration)
+ {
+ configuration.add("com.example.rest.entities");
+ }</code></pre>
+</div></div><h2 class="auto-cursor-target"
id="RESTSupport(5.8.0+)(pageisworkinprogress)-IntegrationwithJacksonDatabindwithtapestry-rest-jackson">Integration
with Jackson Databind with tapestry-rest-jackson</h2><p>JSON has been widely
used as a data interchange format in REST endpoints, while Jackson Databind is
maybe the mostly used Java library for JSON mapping.
tapestry-rest-jackson </p><p>automates the usage of Jackson Databind in
Tapestry, defining an <code>ObjectMapperSource</code> service,
contributing <code>ComponentEventResultProcessor</code> and
<code>HttpRequestBodyConverter</code> implementations  for  all
mapped entity classes (as defined by the <code>MappedEntityManager</code>
service) and implementing the generation of JSON schemas for OpenAPI
descriptions of mapped entity classes using <a class="external-link"
href="https://victools.github.io/jsonschema-generator/"
rel="nofollow">victools/jsonschema-generator</a>. </p><p>The
<code>ObjectMappe
rSource</code> service defines how tapestry-rest-jackson will get an
<code>ObjectMapper</code> instance to use for a given entity class. It has an
ordered configuration of <code>ObjectMapperSource</code>. It has a single
method, <code>ObjectMapper get(Class<?> clasz)</code>. When it's called,
it goes through all the contributed instances calling the same method on them
until one returns a non-null value. When a non-null value is returned, the
service method returns it. If none is found, the fallback is always returning
the same object returned by <code>new ObjectMapper()</code>. Any customizations
to the <code>ObjectMapper</code> instance should be done as contributions to
the <code>ObjectMapperSource</code> service. Here's one example that defines
which date format should be used for all entity classes:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre><code class="language-java"></code></pre>
+</div></div><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-AutomaticgenerationofOpenAPI3.0(Swagger)descriptions">Automatic
generation of OpenAPI 3.0 (Swagger) descriptions</h2><p>Tapestry provides an
out-of-the-box OpenAPI 3.0 (Swagger) description generator driven by the REST
endpoints event handlers (i.e. the ones handling the events listed in the table
in the top of this page), configuration symbols and internationalization
messages (i.e. app.properties). The description is in the JSON
format.</p><p>It's disabled by default. It's enabled by setting the
<code>tapestry.publish-openapi-description</code>
(<code>SymbolConstants.PUBLISH_OPENAPI_DEFINITON</code>) configuration symbol
to <code>true</code>. If enabled, it will be available at the
<code>/openapi.json</code> URL. This is configurable by using the
<code>tapestry.openapi-description-path</code>
(<code>SymbolConstants.OPENAPI_DESCRIPTION_PATH</code>) configuration
symbol. </p><h3 id="RESTSupport(5.8.0+)(pageisworkinpr
ogress)-Customizingnames,summariesanddescriptionsusingmessagesandconfigurationsymbols">Customizing
names, summaries and descriptions using messages and configuration
symbols</h3><p>Summaries, names and descriptions and messages are taken from
messages first, configuration symbol second, except for the OpenAPI version,
which is only taken from the <code>tapestry.openapi-version</code>
(<code>SymbolConstants.OPENAPI_VERSION</code>) symbol and has a default value
of <code>3.0.0</code>. Given a message key, the corresponding configuration
symbol is <code>tapestry.[message key]</code> format.</p><p>HTTP method names
are lowercased.</p><p>When building a message key, if it's based on a path, the
starting slash is not removed. For example, the summary for the
<code>/something</code> endpoint for the POST method is
<code>openapi./something.post.summary</code>.</p><p>You can see which messages
and symbols are being looked up by setting the debug level of the
<code>org.apache.tapestry5.intern
al.services.rest.DefaultOpenApiDescriptionGenerator</code> class to
<code>DEBUG</code>.</p><h3
id="RESTSupport(5.8.0+)(pageisworkinprogress)-Furthercustomizations">Further
customizations</h3><p>The generated description can be further customized by
implementing the <code>OpenApiDescriptionGenerator</code> interface and
contributing it to the <code>OpenApiDescriptionGenerator</code> service. The
<code>JSONObject generate(JSONObject documentation)</code> method will receive
the generated description and it can be changed by using the
<code>JSONObject</code> methods. The return value should be the same object
received as a parameter.</p><h2
id="RESTSupport(5.8.0+)(pageisworkinprogress)-tapestry-openapi-viewer">tapestry-openapi-viewer</h2><p>The
tapestry-openapi-viewer Tapestry subproject/JAR embeds the open source <a
class="external-link" href="https://swagger.io/tools/swagger-ui/"
rel="nofollow">Swagger-UI</a> OpenAPI/Swagger and makes it available at the
<code>/openapiviewer</code> U
RL. No configuration is needed other than including the JAR in the
classpath.</p><p></p></div>
+ </div>
+ <!-- /// Content End -->
+ </div>
+ </div>
+ </div>
+ </div>
+ </article>
+
+ <!-- /// Footer Start -->
+ <div id="footer"><p>Apache Tapestry, Tapestry, Apache, the Apache feather
logo, and the Apache Tapestry project logo are trademarks of The Apache
Software Foundation.</p><p><br clear="none"><img class="wysiwyg-unknown-macro"
src="https://cwiki.apache.org/confluence/plugins/servlet/confluence/placeholder/unknown-macro?name=html&locale=en_GB&version=2"><br
clear="none"></p><p><br clear="none"></p></div>
+ <!-- /// Footer End -->
+</body>
+</html>