You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2021/10/14 21:49:08 UTC
[tapestry-5] branch rest updated: TAP5-2696: generating OpenAPI for
path and query parameters
This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch rest
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/rest by this push:
new a1f8060 TAP5-2696: generating OpenAPI for path and query parameters
a1f8060 is described below
commit a1f8060d694a4a52c6e09925593a3076e4726555
Author: Thiago H. de Paula Figueiredo <th...@arsmachina.com.br>
AuthorDate: Thu Oct 14 18:48:51 2021 -0300
TAP5-2696: generating OpenAPI for path and query parameters
---
.../DefaultOpenApiDescriptionGenerator.java | 96 ++++++++++++++++------
.../app1/base/AbstractRestDemoPage.java | 27 ++++++
.../integration/app1/base/BaseRestDemoPage.java | 17 +++-
3 files changed, 112 insertions(+), 28 deletions(-)
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultOpenApiDescriptionGenerator.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultOpenApiDescriptionGenerator.java
index c3ed3bb..89cf549 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultOpenApiDescriptionGenerator.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultOpenApiDescriptionGenerator.java
@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.RequestParameter;
import org.apache.tapestry5.annotations.StaticActivationContextValue;
import org.apache.tapestry5.commons.Messages;
import org.apache.tapestry5.http.services.BaseURLSource;
@@ -42,7 +43,6 @@ import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.model.ComponentModel;
import org.apache.tapestry5.runtime.Component;
import org.apache.tapestry5.services.ComponentClassResolver;
-import org.apache.tapestry5.services.ComponentSource;
import org.apache.tapestry5.services.OpenApiDescriptionGenerator;
import org.apache.tapestry5.services.PageRenderLinkSource;
import org.apache.tapestry5.services.messages.ComponentMessagesSource;
@@ -78,8 +78,6 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
final private PageRenderLinkSource pageRenderLinkSource;
- final private ComponentSource componentSource;
-
final private static String KEY_PREFIX = "openapi.";
public DefaultOpenApiDescriptionGenerator(
@@ -89,8 +87,7 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
final ThreadLocale threadLocale,
final PageSource pageSource,
final ComponentClassResolver componentClassResolver,
- final PageRenderLinkSource pageRenderLinkSource,
- final ComponentSource componentSource)
+ final PageRenderLinkSource pageRenderLinkSource)
{
super();
this.baseUrlSource = baseUrlSource;
@@ -100,7 +97,6 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
this.pageSource = pageSource;
this.componentClassResolver = componentClassResolver;
this.pageRenderLinkSource = pageRenderLinkSource;
- this.componentSource = componentSource;
messages = new ThreadLocal<>();
failedPageNames = new HashSet<>();
}
@@ -161,7 +157,7 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
JSONObject info = new JSONObject();
putIfNotEmpty(info, "title", SymbolConstants.OPENAPI_TITLE);
putIfNotEmpty(info, "description", SymbolConstants.OPENAPI_DESCRIPTION);
- info.put("version", getValueFromSymbol(SymbolConstants.OPENAPI_APPLICATION_VERSION).orElse("?"));
+ info.put("version", getValueFromSymbolNoPrefix(SymbolConstants.OPENAPI_APPLICATION_VERSION).orElse("?"));
documentation.put("info", info);
}
@@ -250,28 +246,65 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
else
{
- final JSONObject methodDocumentation = new JSONObject();
+ final JSONObject methodDescription = new JSONObject();
- putIfNotEmpty(methodDocumentation, "summary", getValue(method, uri, httpMethod, "summary"));
- putIfNotEmpty(methodDocumentation, "description", getValue(method, uri, httpMethod, "description"));
+ putIfNotEmpty(methodDescription, "summary", getValue(method, uri, httpMethod, "summary"));
+ putIfNotEmpty(methodDescription, "description", getValue(method, uri, httpMethod, "description"));
JSONArray methodTags = new JSONArray();
methodTags.add(tagName);
- methodDocumentation.put("tags", methodTags);
-
- JSONObject responses = new JSONObject();
- JSONObject defaultResponse = new JSONObject();
- int statusCode = httpMethod.equals("post") ?
- HttpServletResponse.SC_CREATED : HttpServletResponse.SC_OK;
- putIfNotEmpty(defaultResponse, "description", getValue(method, uri, httpMethod, statusCode));
- responses.put(String.valueOf(statusCode), defaultResponse);
+ methodDescription.put("tags", methodTags);
- methodDocumentation.put("responses", responses);
+ processResponses(method, uri, httpMethod, methodDescription);
+
+ processParameters(method, uri, httpMethod, methodDescription);
- path.put(httpMethod, methodDocumentation);
+ path.put(httpMethod, methodDescription);
+ }
+ }
+
+ private void processParameters(Method method, final String uri, final String httpMethod, final JSONObject methodDescription) {
+ JSONArray parametersAsJsonArray = new JSONArray();
+ for (Parameter parameter : method.getParameters())
+ {
+ final JSONObject parameterDescription = new JSONObject();
+ if (!isIgnored(parameter) &&
+ parameter.getAnnotation(StaticActivationContextValue.class) == null)
+ {
+ parameterDescription.put("in", "path");
+ }
+ else if (parameter.getAnnotation(RequestParameter.class) != null)
+ {
+ parameterDescription.put("in", "query");
+ }
+ if (!parameterDescription.isEmpty())
+ {
+ Optional<String> parameterName = getValue(method, uri, httpMethod, parameter, "name");
+ parameterDescription.put("name", parameterName.orElse(parameter.getName()));
+ getValue(method, uri, httpMethod, parameter, "description")
+ .ifPresent((v) -> parameterDescription.put("description", v));
+
+ parametersAsJsonArray.add(parameterDescription);
+ }
+ }
+
+ if (!parametersAsJsonArray.isEmpty())
+ {
+ methodDescription.put("parameters", parametersAsJsonArray);
}
}
+ private void processResponses(Method method, final String uri, final String httpMethod, final JSONObject methodDescription) {
+ JSONObject responses = new JSONObject();
+ JSONObject defaultResponse = new JSONObject();
+ int statusCode = httpMethod.equals("post") ?
+ HttpServletResponse.SC_CREATED : HttpServletResponse.SC_OK;
+ putIfNotEmpty(defaultResponse, "description", getValue(method, uri, httpMethod, statusCode));
+ responses.put(String.valueOf(statusCode), defaultResponse);
+
+ methodDescription.put("responses", responses);
+ }
+
private void addElementsIfNotPresent(JSONArray accumulator, JSONArray array)
{
if (array != null)
@@ -317,21 +350,31 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
{
return getValue(method, path + "." + httpMethod + "." + property, true);
}
+
+ public Optional<String> getValue(Method method, String path, String httpMethod, Parameter parameter, String property)
+ {
+ return getValue(method, path, httpMethod, "parameter." + parameter.getName(), property);
+ }
public Optional<String> getValue(Method method, String path, String httpMethod, int statusCode)
{
- Optional<String> value = getValue(method, path + "." + httpMethod + ".response." + String.valueOf(statusCode), true);
+ return getValue(method, path, httpMethod, "response", String.valueOf(statusCode));
+ }
+
+ public Optional<String> getValue(Method method, String path, String httpMethod, String middle, String propertyName)
+ {
+ Optional<String> value = getValue(method, path + "." + httpMethod + "." + middle + "." + String.valueOf(propertyName), true);
if (!value.isPresent())
{
- value = getValue(method, httpMethod + ".response." + String.valueOf(statusCode), false);
+ value = getValue(method, httpMethod + "." + middle + "." + propertyName, false);
}
if (!value.isPresent())
{
- value = getValue(method, "response." + String.valueOf(statusCode), false);
+ value = getValue(method, middle + "." + propertyName, false);
}
if (!value.isPresent())
{
- value = getValue("response." + String.valueOf(statusCode));
+ value = getValue(middle + "." + propertyName);
}
return value;
}
@@ -490,8 +533,11 @@ public class DefaultOpenApiDescriptionGenerator implements OpenApiDescriptionGen
private Optional<String> getValueFromSymbol(String key)
{
+ return getValueFromSymbolNoPrefix("tapestry." + key);
+ }
+
+ private Optional<String> getValueFromSymbolNoPrefix(final String symbol) {
String value;
- final String symbol = "tapestry." + key;
logSymbolLookup(symbol);
try
{
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/AbstractRestDemoPage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/AbstractRestDemoPage.java
new file mode 100644
index 0000000..ca419a5
--- /dev/null
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/AbstractRestDemoPage.java
@@ -0,0 +1,27 @@
+// Licensed 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.
+package org.apache.tapestry5.integration.app1.base;
+
+import org.apache.tapestry5.EventConstants;
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.StaticActivationContextValue;
+import org.apache.tapestry5.util.TextStreamResponse;
+
+public class AbstractRestDemoPage {
+
+ @OnEvent(EventConstants.HTTP_GET)
+ protected Object abstractSuperclassEndpoint(@StaticActivationContextValue("abstract") String abstractValue)
+ {
+ return new TextStreamResponse("text/plain", abstractValue);
+ }
+
+}
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/BaseRestDemoPage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/BaseRestDemoPage.java
index 19fa7a7..20fbc4b 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/BaseRestDemoPage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/BaseRestDemoPage.java
@@ -13,11 +13,12 @@ package org.apache.tapestry5.integration.app1.base;
import org.apache.tapestry5.EventConstants;
import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.RequestParameter;
import org.apache.tapestry5.annotations.StaticActivationContextValue;
import org.apache.tapestry5.http.services.Response;
import org.apache.tapestry5.util.TextStreamResponse;
-public class BaseRestDemoPage {
+public class BaseRestDemoPage extends AbstractRestDemoPage {
public static final String EXTRA_HTTP_HEADER = "X-Event";
@@ -38,9 +39,19 @@ public class BaseRestDemoPage {
}
@OnEvent(EventConstants.HTTP_GET)
- protected Object superclassEndpoint(@StaticActivationContextValue("superclassEndpoint") String parameter)
+ protected Object superclassEndpoint(@StaticActivationContextValue("superclassEndpoint") String pathParameter)
{
- return new TextStreamResponse("text/plain", parameter);
+ return new TextStreamResponse("text/plain", pathParameter);
+ }
+
+ @OnEvent(EventConstants.HTTP_GET)
+ protected Object withParameters(
+ @StaticActivationContextValue("parametersTest") String staticParameter,
+ @RequestParameter(value = "fromQueryString", allowBlank = true) String queryParameter,
+ String pathParameter)
+ {
+ return new TextStreamResponse("text/plain",
+ String.join(":", staticParameter, pathParameter, queryParameter));
}
}