Author: buildbot
Date: Sun Jan 9 21:20:56 2022
New Revision: 1077937
Log:
Production update by buildbot for tapestry
Modified:
websites/production/tapestry/content/cache/main.pageCache
websites/production/tapestry/content/rest-support-page-is-work-in-progress.html
Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/rest-support-page-is-work-in-progress.html
==============================================================================
---
websites/production/tapestry/content/rest-support-page-is-work-in-progress.html
(original)
+++
websites/production/tapestry/content/rest-support-page-is-work-in-progress.html
Sun Jan 9 21:20:56 2022
@@ -106,7 +106,90 @@ Object save(@RequestBody User user) {
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>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></p></div>
+</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(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(pageisworkinprogress)-Contentresponses">Content
responses</h3><p>For content responses, Tapestry has out-of-the-box support for
<code>StreamRespo
nse</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(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
panelConten
t 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><p></p></div>
</div>
<!-- /// Content End -->
</div>