You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bu...@apache.org on 2022/01/09 21:20:56 UTC
svn commit: r1077937 - in /websites/production/tapestry/content: cache/main.pageCache rest-support-page-is-work-in-progress.html
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>