You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/01/20 18:29:03 UTC
[2/3] juneau git commit: Refactor RestInfoProvider.
http://git-wip-us.apache.org/repos/asf/juneau/blob/62b041ab/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProviderDefault.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProviderDefault.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProviderDefault.java
index 11cad76..983856a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProviderDefault.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProviderDefault.java
@@ -16,11 +16,13 @@ import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.dto.swagger.SwaggerBuilder.*;
import static org.apache.juneau.internal.ReflectionUtils.*;
+import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.*;
import org.apache.juneau.dto.swagger.*;
import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.rest.annotation.*;
@@ -31,8 +33,6 @@ import org.apache.juneau.svl.*;
*
* <p>
* Subclasses can override these methods to tailor how HTTP REST resources are documented.
- * Subclasses MUST implement a public constructor that takes in a {@link RestContext} object.
- *
*
* <h5 class='topic'>Additional Information</h5>
* <ul>
@@ -125,20 +125,17 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Returned objects are cached for later quick-lookup.
*
* @param req The incoming HTTP request.
- * @return The parsed swagger object, or <jk>null</jk> if the swagger file could not be found.
- * @throws RestException
+ * @return The parsed swagger object, or <jk>null</jk> if none could be found.
+ * @throws Exception
+ * If swagger file was not valid JSON.
*/
@Override /* RestInfoProvider */
- public Swagger getSwaggerFromFile(RestRequest req) throws RestException {
+ public Swagger getSwaggerFromFile(RestRequest req) throws Exception {
Locale locale = req.getLocale();
Swagger s = swaggers.get(locale);
if (s == null) {
- try {
- s = context.getClasspathResource(Swagger.class, MediaType.JSON, getClass().getSimpleName() + ".json", locale);
- swaggers.putIfAbsent(locale, s == null ? Swagger.NULL : s);
- } catch (Exception e) {
- throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
- }
+ s = context.getClasspathResource(Swagger.class, MediaType.JSON, getClass().getSimpleName() + ".json", locale);
+ swaggers.putIfAbsent(locale, s == null ? Swagger.NULL : s);
}
return s == Swagger.NULL ? null : s;
}
@@ -146,98 +143,137 @@ public class RestInfoProviderDefault implements RestInfoProvider {
/**
* Returns the localized swagger for this REST resource.
*
+ * <p>
+ * Subclasses can override this method to customize the Swagger.
+ *
* @param req The incoming HTTP request.
- * @return A new Swagger instance.
- * @throws RestException
+ * @return
+ * A new Swagger instance.
+ * <br>Never <jk>null</jk>.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public Swagger getSwagger(RestRequest req) throws RestException {
- try {
- // If a file is defined, use that.
- Swagger s = req.getSwaggerFromFile();
- if (s != null)
- return s;
-
- s = swagger(
- info(getTitle(req), getVersion(req))
- .contact(getContact(req))
- .license(getLicense(req))
- .description(getDescription(req))
- .termsOfService(getTermsOfService(req))
- )
- .consumes(req.getSupportedAcceptTypes())
- .produces(req.getSupportedContentTypes())
- .tags(getTags(req))
- .externalDocs(getExternalDocs(req));
-
- for (RestJavaMethod sm : context.getCallMethods().values()) {
- if (sm.isRequestAllowed(req)) {
- Operation o = sm.getSwaggerOperation(req);
- s.path(
- sm.getPathPattern(),
- sm.getHttpMethod().toLowerCase(),
- o
- );
- }
- }
+ public Swagger getSwagger(RestRequest req) throws Exception {
+
+ // If a file is defined, use that.
+ Swagger s = getSwaggerFromFile(req);
+ if (s != null)
return s;
- } catch (RestException e) {
- throw e;
- } catch (Exception e) {
- throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+
+ s = swagger(
+ info(getTitle(req), getVersion(req))
+ .contact(getContact(req))
+ .license(getLicense(req))
+ .description(getDescription(req))
+ .termsOfService(getTermsOfService(req))
+ )
+ .consumes(getConsumes(req))
+ .produces(getProduces(req))
+ .tags(getTags(req))
+ .externalDocs(getExternalDocs(req));
+
+ for (RestJavaMethod sm : context.getCallMethods().values()) {
+ if (sm.isRequestAllowed(req)) {
+ Method m = sm.method;
+ Operation o = operation()
+ .operationId(getMethodOperationId(m, req))
+ .description(getMethodDescription(m, req))
+ .tags(getMethodTags(m, req))
+ .summary(getMethodSummary(m, req))
+ .externalDocs(getMethodExternalDocs(m, req))
+ .parameters(getMethodParameters(m, req))
+ .responses(getMethodResponses(m, req));
+
+ if (isDeprecated(m, req))
+ o.deprecated(true);
+
+ o.consumes(getMethodConsumes(m, req));
+ o.produces(getMethodProduces(m, req));
+
+ s.path(
+ sm.getPathPattern(),
+ sm.getHttpMethod().toLowerCase(),
+ o
+ );
+ }
}
+
+ return s;
}
/**
- * Returns the localized summary of the specified java method on this servlet.
+ * Returns the localized operation ID of the specified java method.
*
* <p>
- * Subclasses can override this method to provide their own summary.
+ * Subclasses can override this method to provide their own operation ID.
*
* <p>
- * The default implementation returns the summary from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestMethod#summary() @RestMethod.summary()} annotation on the method.
- * <li><ck>[ClassName].[javaMethodName].summary</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>[javaMethodName].summary</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * </ol>
+ * The default implementation simply returns the Java method name.
*
- * @param javaMethodName The name of the Java method whose description we're retrieving.
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
* @param req The current request.
- * @return The localized summary of the method, or a blank string if no summary was found.
+ * @return The localized operation ID of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getMethodSummary(String javaMethodName, RestRequest req) {
- RestJavaMethod m = context.getCallMethods().get(javaMethodName);
- if (m != null)
- return m.getSummary(req);
- return "";
+ public String getMethodOperationId(Method method, RestRequest req) throws Exception {
+ return method.getName();
}
/**
- * Returns the localized summary of the java method invoked on the specified request.
+ * Returns the localized summary of the specified java method on this servlet.
*
* <p>
* Subclasses can override this method to provide their own summary.
*
* <p>
- * The default implementation returns the summary from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestMethod#summary() @RestMethod.summary()} annotation on the method.
- * <li><ck>[ClassName].[javaMethodName].summary</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>[javaMethodName].summary</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestMethod#summary() @RestMethod.summary()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(summary=<js>"Summary of my method"</js>)
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(summary=<js>"$L{myLocalizedSummary}"</js>)
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized string from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].summary</ck>
+ * <li><ck>[javaMethodName].summary</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link RestMethod#summary() @RestMethod.summary()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.myMethod.summary</ck> = <cv>Summary of my method.</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.summary</ck> = <cv>$C{MyStrings/MyClass.myMethod.summary}</cv>
+ * </p>
* </ol>
*
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
* @param req The current request.
- * @return The localized summary of the method, or a blank string if no summary was found.
+ * @return The localized summary of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getMethodSummary(RestRequest req) {
- return getMethodSummary(req.getJavaMethod().getName(), req);
+ public String getMethodSummary(Method method, RestRequest req) throws Exception {
+ VarResolverSession vr = req.getVarResolverSession();
+
+ String s = method.getAnnotation(RestMethod.class).summary();
+ if (s.isEmpty())
+ s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".summary");
+ if (s != null)
+ return vr.resolve(s);
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ return o == null ? null : o.getSummary();
}
/**
@@ -247,49 +283,539 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own description.
*
* <p>
- * The default implementation returns the description from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestMethod#description() @RestMethod.description()} annotation on the method.
- * <li><ck>[ClassName].[javaMethodName].description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>[javaMethodName].description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestMethod#description() @RestMethod.description()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(description=<js>"Description of my method"</js>)
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(description=<js>"$L{myLocalizedDescription}"</js>)
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized string from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].description</ck>
+ * <li><ck>[javaMethodName].description</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link RestMethod#description() @RestMethod.description()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.myMethod.description</ck> = <cv>Description of my method.</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.description</ck> = <cv>$C{MyStrings/MyClass.myMethod.description}</cv>
+ * </p>
* </ol>
*
- * @param javaMethodName The name of the Java method whose description we're retrieving.
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
* @param req The current request.
- * @return The localized description of the method, or a blank string if no description was found.
+ * @return The localized description of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getMethodDescription(String javaMethodName, RestRequest req) {
- RestJavaMethod m = context.getCallMethods().get(javaMethodName);
- if (m != null)
- return m.getDescription(req);
- return "";
+ public String getMethodDescription(Method method, RestRequest req) throws Exception {
+ VarResolverSession vr = req.getVarResolverSession();
+
+ String s = method.getAnnotation(RestMethod.class).description();
+ if (s.isEmpty())
+ s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".description");
+ if (s != null)
+ return vr.resolve(s);
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ return o == null ? null : o.getDescription();
}
/**
- * Returns the localized description of the invoked java method on the specified request.
+ * Returns the localized Swagger tags for this Java method.
*
* <p>
- * Subclasses can override this method to provide their own description.
+ * Subclasses can override this method to provide their own tags.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link MethodSwagger#tags() @MethodSwagger.tags()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(tags=<js>"foo,bar,baz"</js>)
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(tags=<js>"$L{myLocalizedTags}"</js>)
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized string from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].tags</ck>
+ * <li><ck>[javaMethodName].tags</ck>
+ * </ol>
+ * <br>Value can be a comma-delimited list or JSON array.
+ * <br>Value can contain any SVL variables defined on the {@link MethodSwagger#tags() @MethodSwagger.tags()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Comma-delimited list</cc>
+ * <ck>MyClass.myMethod.tags</ck> = <cv>foo, bar, baz</cv>
+ *
+ * <cc>// JSON array</cc>
+ * <ck>MyClass.myMethod.tags</ck> = <cv>["foo", "bar", "baz"]</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.description</ck> = <cv>$C{MyStrings/MyClass.myMethod.tags}</cv>
+ * </p>
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return The localized tags of the method, or <jk>null</jk> if none were found.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public List<String> getMethodTags(Method method, RestRequest req) throws Exception {
+ JsonParser p = JsonParser.DEFAULT;
+ VarResolverSession vr = req.getVarResolverSession();
+
+ String s = method.getAnnotation(RestMethod.class).swagger().tags();
+ if (s.isEmpty())
+ s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".tags");
+ if (s != null) {
+ s = vr.resolve(s);
+ if (StringUtils.isObjectList(s))
+ return p.parse(s, ArrayList.class, String.class);
+ return Arrays.asList(StringUtils.split(s));
+ }
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ return o == null ? null : o.getTags();
+ }
+
+ /**
+ * Returns the localized external documentation of the specified java method on this servlet.
+ *
+ * <p>
+ * Subclasses can override this method to provide their own external documentation.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link MethodSwagger#externalDocs() @MethodSwagger.externalDocs()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(externalDocs=<js>"{description:'Find more info here',url:'https://swagger.io'}"</js>)
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(externalDocs=<js>"$L{myLocalizedExternalDocs}"</js>)
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized string from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].externalDocs</ck>
+ * <li><ck>[javaMethodName].externalDocs</ck>
+ * </ol>
+ * <br>Value is a JSON representation of a {@link ExternalDocumentation} object.
+ * <br>Value can contain any SVL variables defined on the {@link MethodSwagger#externalDocs() @MethodSwagger.externalDocs()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.myMethod.externalDocs</ck> = <cv>{description:"Find more info here",url:"https://swagger.io"}</js>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.externalDocs</ck> = <cv>$C{MyStrings/MyClass.myMethod.externalDocs}</cv>
+ * </p>
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return The localized external documentation of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public ExternalDocumentation getMethodExternalDocs(Method method, RestRequest req) throws Exception {
+ JsonParser p = JsonParser.DEFAULT;
+ VarResolverSession vr = req.getVarResolverSession();
+
+ String s = method.getAnnotation(RestMethod.class).swagger().externalDocs();
+ if (s.isEmpty())
+ s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".externalDocs");
+ if (s != null)
+ return p.parse(vr.resolve(s), ExternalDocumentation.class);
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ return o == null ? null : o.getExternalDocs();
+ }
+
+ /**
+ * Returns the localized parameter info for the specified java method.
+ *
+ * <p>
+ * Subclasses can override this method to provide their own parameter info.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>Operation information from swagger file.
+ * <li>{@link MethodSwagger#parameters() @MethodSwagger.parameters()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(
+ * parameters={
+ * <ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"a"</js>, description=<js>"The 'a' attribute"</js>)
+ * }
+ * )
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(
+ * parameters={
+ * <ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"a"</js>, description=<js>"$L{myLocalizedParamADescription}"</js>)
+ * }
+ * )
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].parameters</ck>
+ * <li><ck>[javaMethodName].parameters</ck>
+ * </ol>
+ * <br>Value is a JSON representation of a <code>{@link ParameterInfo}[]</code> object.
+ * <br>Value can contain any SVL variables defined on the {@link MethodSwagger#parameters() @MethodSwagger.parameters()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.myMethod.parameters</ck> = <cv>[{name:"a",in:"path",description:"The ''a'' attribute"}]</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.parameters</ck> = <cv>$C{MyStrings/MyClass.myMethod.parameters}</cv>
+ * </p>
+ * <li>Information gathered directly from the parameters on the Java method.
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return The localized parameter info of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public List<ParameterInfo> getMethodParameters(Method method, RestRequest req) throws Exception {
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ if (o != null && o.getParameters() != null)
+ return o.getParameters();
+
+ VarResolverSession vr = req.getVarResolverSession();
+ JsonParser jp = JsonParser.DEFAULT;
+ Map<String,ParameterInfo> m = new TreeMap<>();
+
+ // First parse @RestMethod.parameters() annotation.
+ for (org.apache.juneau.rest.annotation.Parameter v : method.getAnnotation(RestMethod.class).swagger().parameters()) {
+ String in = vr.resolve(v.in());
+ ParameterInfo p = parameterInfo(in, vr.resolve(v.name()));
+
+ if (! v.description().isEmpty())
+ p.description(vr.resolve(v.description()));
+ if (v.required())
+ p.required(v.required());
+
+ if ("body".equals(in)) {
+ if (! v.schema().isEmpty())
+ p.schema(jp.parse(vr.resolve(v.schema()), SchemaInfo.class));
+ } else {
+ if (v.allowEmptyValue())
+ p.allowEmptyValue(v.allowEmptyValue());
+ if (! v.collectionFormat().isEmpty())
+ p.collectionFormat(vr.resolve(v.collectionFormat()));
+ if (! v._default().isEmpty())
+ p._default(vr.resolve(v._default()));
+ if (! v.format().isEmpty())
+ p.format(vr.resolve(v.format()));
+ if (! v.items().isEmpty())
+ p.items(jp.parse(vr.resolve(v.items()), Items.class));
+ p.type(vr.resolve(v.type()));
+ }
+ m.put(p.getIn() + '.' + p.getName(), p);
+ }
+
+ // Next, look in resource bundle.
+ String s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".parameters");
+ if (s != null) {
+ for (ParameterInfo pi : jp.parse(vr.resolve(s), ParameterInfo[].class)) {
+ String key = pi.getIn() + '.' + pi.getName();
+ ParameterInfo p = m.get(key);
+ if (p == null)
+ m.put(key, pi);
+ else
+ p.copyFrom(pi);
+ }
+ }
+
+ // Finally, look for parameters defined on method.
+ for (RestParam mp : context.getRestParams(method)) {
+ RestParamType in = mp.getParamType();
+ if (in != RestParamType.OTHER) {
+ String k2 = in.toString() + '.' + (in == RestParamType.BODY ? null : mp.getName());
+ ParameterInfo p = m.get(k2);
+ if (p == null) {
+ p = parameterInfoStrict(in.toString(), mp.getName());
+ m.put(k2, p);
+ }
+ }
+ }
+
+ return m.isEmpty() ? null : new ArrayList<>(m.values());
+ }
+
+ /**
+ * Returns the localized response info for the specified java method.
+ *
+ * <p>
+ * Subclasses can override this method to provide their own parameter info.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>Operation information from swagger file.
+ * <li>{@link MethodSwagger#responses() @MethodSwagger.responses()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(
+ * responses={
+ * <ja>@Response</ja>(
+ * value=302,
+ * description=<js>"Thing wasn't found here"</js>,
+ * headers={
+ * <ja>@Parameter</ja>(name=<js>"Location"</js>, description=<js>"The place to find the thing"</js>)
+ * }
+ * )
+ * }
+ * )
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(
+ * responses={
+ * <ja>@Response</ja>(
+ * value=302,
+ * description=<js>"Thing wasn't found here"</js>,
+ * headers={
+ * <ja>@Parameter</ja>(name=<js>"Location"</js>, description=<js>"$L{myLocalizedResponseDescription}"</js>)
+ * }
+ * )
+ * }
+ * )
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].[javaMethodName].responses</ck>
+ * <li><ck>[javaMethodName].responses</ck>
+ * </ol>
+ * <br>Value is a JSON representation of a <code>Map<Integer,{@link ResponseInfo}></code> object.
+ * <br>Value can contain any SVL variables defined on the {@link MethodSwagger#responses() @MethodSwagger.responses()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.myMethod.responses</ck> = <cv>{302:{description:'Thing wasn''t found here',headers={Location:{description:"The place to find the thing"}}}</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.myMethod.responses</ck> = <cv>$C{MyStrings/MyClass.myMethod.responses}</cv>
+ * </p>
+ * <li>Information gathered directly from the parameters on the Java method.
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return The localized response info of the method, or <jk>null</jk> if none was found.
+ * @throws Exception
+ */
+ @SuppressWarnings("unchecked")
+ @Override /* RestInfoProvider */
+ public Map<Integer,ResponseInfo> getMethodResponses(Method method, RestRequest req) throws Exception {
+
+ Operation o = getSwaggerOperationFromFile(method, req);
+ if (o != null && o.getResponses() != null)
+ return o.getResponses();
+
+ VarResolverSession vr = req.getVarResolverSession();
+ JsonParser jp = JsonParser.DEFAULT;
+ Map<Integer,ResponseInfo> m = new TreeMap<>();
+ Map<String,HeaderInfo> m2 = new TreeMap<>();
+
+ // First parse @RestMethod.parameters() annotation.
+ for (Response r : method.getAnnotation(RestMethod.class).swagger().responses()) {
+ int httpCode = r.value();
+ String description = r.description().isEmpty() ? RestUtils.getHttpResponseText(r.value()) : vr.resolve(r.description());
+ ResponseInfo r2 = responseInfo(description);
+
+ if (r.headers().length > 0) {
+ for (org.apache.juneau.rest.annotation.Parameter v : r.headers()) {
+ HeaderInfo h = headerInfoStrict(vr.resolve(v.type()));
+ if (! v.collectionFormat().isEmpty())
+ h.collectionFormat(vr.resolve(v.collectionFormat()));
+ if (! v._default().isEmpty())
+ h._default(vr.resolve(v._default()));
+ if (! v.description().isEmpty())
+ h.description(vr.resolve(v.description()));
+ if (! v.format().isEmpty())
+ h.format(vr.resolve(v.format()));
+ if (! v.items().isEmpty())
+ h.items(jp.parse(vr.resolve(v.items()), Items.class));
+ r2.header(v.name(), h);
+ m2.put(httpCode + '.' + v.name(), h);
+ }
+ }
+ m.put(httpCode, r2);
+ }
+
+ // Next, look in resource bundle.
+ String s = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".responses");
+ if (s != null) {
+ for (Map.Entry<Integer,ResponseInfo> e : ((Map<Integer,ResponseInfo>)jp.parse(vr.resolve(s), Map.class, Integer.class, ResponseInfo.class)).entrySet()) {
+ Integer httpCode = e.getKey();
+ ResponseInfo ri = e.getValue();
+
+ ResponseInfo r = m.get(httpCode);
+ if (r == null)
+ m.put(httpCode, ri);
+ else
+ r.copyFrom(ri);
+ }
+ }
+
+ return m.isEmpty() ? null : m;
+ }
+
+ /**
+ * Returns the supported <code>Accept</code> types the specified Java method.
*
* <p>
- * The default implementation returns the description from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestMethod#description() @RestMethod.description()} annotation on the method.
- * <li><ck>[ClassName].[javaMethodName].description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>[javaMethodName].description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * Subclasses can override this method to provide their own produces info.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestMethod#produces() @RestMethod.supportedAcceptTypes()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(supportedAcceptTypes={<js>"text/json"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(supportedAcceptTypes={<js>"$C{mySupportedProduces}"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Media types defined on the parsers associated with the method.
* </ol>
*
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
* @param req The current request.
- * @return The localized description of the method, or a blank string if no description was found.
+ * @return The supported <code>Accept</code> types of the method, or <jk>null</jk> if none was found
+ * or the list of media types match those of the parent resource class.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getMethodDescription(RestRequest req) {
- return getMethodDescription(req.getJavaMethod().getName(), req);
+ public List<MediaType> getMethodProduces(Method method, RestRequest req) throws Exception {
+ VarResolverSession vr = req.getVarResolverSession();
+ String[] s = method.getAnnotation(RestMethod.class).produces();
+ if (s.length > 0)
+ return Arrays.asList(MediaType.forStrings(vr.resolve(s)));
+ List<MediaType> l = req.getSerializers().getSupportedMediaTypes();
+ return (l.equals(context.getProduces()) ? null : l);
+ }
+
+ /**
+ * Returns the supported <code>Content-Type</code> types the specified Java method.
+ *
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestMethod#consumes() @RestMethod.supportedContentTypes()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ja>@RestMethod</ja>(supportedContentTypes={<js>"text/json"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ja>@RestMethod</ja>(supportedContentTypes={<js>"$C{mySupportedConsumes}"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * <li>Media types defined on the serializers associated with the method.
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return The supported <code>Content-Type</code> types of the method, or <jk>null</jk> if none was found
+ * or the list of media types match those of the parent resource class.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public List<MediaType> getMethodConsumes(Method method, RestRequest req) throws Exception {
+ VarResolverSession vr = req.getVarResolverSession();
+ String[] s = method.getAnnotation(RestMethod.class).consumes();
+ if (s.length > 0)
+ return Arrays.asList(MediaType.forStrings(vr.resolve(s)));
+ List<MediaType> l = req.getParsers().getSupportedMediaTypes();
+ return (l.equals(context.getConsumes()) ? null : l);
+ }
+
+ /**
+ * Returns whether the specified method is deprecated
+ *
+ * <p>
+ * The default implementation returns the value from the following location:
+ * <ol class='spaced-list'>
+ * <li>{@link MethodSwagger#deprecated() @MethodSwagger.deprecated()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <ja>@RestMethod</ja>(
+ * swagger=<ja>@MethodSwagger</ja>(
+ * deprecated=<jk>true</jk>
+ * )
+ * )
+ * <jk>public</jk> Object myMethod() {...}
+ * </p>
+ * </ol>
+ *
+ * @param method The Java method annotated with {@link RestMethod @RestMethod}.
+ * @param req The current request.
+ * @return <jk>true</jk> if the method is deprecated.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public boolean isDeprecated(Method method, RestRequest req) throws Exception {
+ return method.getAnnotation(RestMethod.class).swagger().deprecated();
}
/**
@@ -299,24 +825,45 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own site name.
*
* <p>
- * The default implementation returns the description from the following locations (whichever matches first):
- * <ol>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
* <li>{@link RestResource#siteName() @RestResource.siteName()} annotation on this class, and then any parent classes.
- * <li><ck>[ClassName].siteName</ck> property in resource bundle identified by
- * {@link RestResource#messages() @ResourceBundle.messages()} annotation for this class, then any parent
- * classes.
- * <li><ck>siteName</ck> in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
- * annotation for this class, then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(siteName=<js>"My Site"</js>)
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(siteName=<js>"$L{myLocalizedSiteName}"</js>)
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].siteName</ck>
+ * <li><ck>siteName</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link RestResource#siteName() @RestResource.siteName()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.siteName</ck> = <cv>My Site</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.siteName</ck> = <cv>$C{MyStrings/MyClass.siteName}</cv>
+ * </p>
* </ol>
*
* @param req The current request.
- * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+ * @return The localized site name of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getSiteName(RestRequest req) {
+ public String getSiteName(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
- if (this.siteName != null)
- return vr.resolve(this.siteName);
+ if (siteName != null)
+ return vr.resolve(siteName);
String siteName = context.getMessages().findFirstString(req.getLocale(), "siteName");
if (siteName != null)
return vr.resolve(siteName);
@@ -330,29 +877,50 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own title.
*
* <p>
- * The default implementation returns the description from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestResource#title() @RestResource.title()} annotation on this class, and then any parent classes.
- * <li><ck>[ClassName].title</ck> property in resource bundle identified by
- * {@link RestResource#messages() @ResourceBundle.messages()} annotation for this class, then any parent
- * classes.
- * <li><ck>title</ck> in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
- * annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestResource#title() @RestResource.siteName()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(title=<js>"My Resource"</js>)
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(title=<js>"$L{myLocalizedTitle}"</js>)
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].title</ck>
+ * <li><ck>title</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link RestResource#title() @RestResource.title()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.title</ck> = <cv>My Resource</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.title</ck> = <cv>$C{MyStrings/MyClass.title}</cv>
+ * </p>
* <li><ck>/info/title</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
- * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+ * @return The localized title of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getTitle(RestRequest req) {
+ public String getTitle(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
- if (this.title != null)
- return vr.resolve(this.title);
+ if (title != null)
+ return vr.resolve(title);
String title = context.getMessages().findFirstString(req.getLocale(), "title");
if (title != null)
return vr.resolve(title);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getTitle();
return null;
@@ -365,29 +933,50 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own description.
*
* <p>
- * The default implementation returns the description from the following locations (whichever matches first):
- * <ol>
- * <li>{@link RestResource#description() @RestResource.description()} annotation on this class, and then any
- * parent classes.
- * <li><ck>[ClassName].description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>description</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link RestResource#description() @RestResource.description()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(description=<js>"My Resource"</js>)
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(description=<js>"$L{myLocalizedDescription}"</js>)
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].description</ck>
+ * <li><ck>description</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link RestResource#description() @RestResource.description()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.description</ck> = <cv>My Resource</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.description</ck> = <cv>$C{MyStrings/MyClass.description}</cv>
+ * </p>
* <li><ck>/info/description</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
- * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+ * @return The localized description of this REST resource, or <jk>null</jk> if none was was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getDescription(RestRequest req) {
+ public String getDescription(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
- if (this.description != null)
- return vr.resolve(this.description);
+ if (description != null)
+ return vr.resolve(description);
String description = context.getMessages().findFirstString(req.getLocale(), "description");
if (description != null)
return vr.resolve(description);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getDescription();
return null;
@@ -400,32 +989,57 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own contact information.
*
* <p>
- * The default implementation returns the contact information from the following locations (whichever matches first):
- * <ol>
- * <li>{@link ResourceSwagger#contact() @ResourceSwagger.contact()} annotation on this class, and then any parent
- * classes.
- * <li><ck>[ClassName].contact</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>contact</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#contact() @ResourceSwagger.contact()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(contact=<js>"{name:'John Smith',email:'john.smith@foo.bar'}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(contact=<js>"$C{MyStrings/MyClass.myContactInfo}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].contact</ck>
+ * <li><ck>contact</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#contact() @ResourceSwagger.contact()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.contact</ck> = <cv>{name:"John Smith",email:"john.smith@foo.bar"}</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.contact</ck> = <cv>$C{MyStrings/MyClass.myContactInfo}</cv>
+ * </p>
* <li><ck>/info/contact</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized contact information of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public Contact getContact(RestRequest req) {
+ public Contact getContact(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
JsonParser jp = JsonParser.DEFAULT;
try {
- if (this.contact != null)
- return jp.parse(vr.resolve(this.contact), Contact.class);
+ if (contact != null)
+ return jp.parse(vr.resolve(contact), Contact.class);
String contact = context.getMessages().findFirstString(req.getLocale(), "contact");
if (contact != null)
return jp.parse(vr.resolve(contact), Contact.class);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getContact();
return null;
@@ -441,32 +1055,57 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own license information.
*
* <p>
- * The default implementation returns the license information from the following locations (whichever matches first):
- * <ol>
- * <li>{@link ResourceSwagger#license() @ResourceSwagger.license()} annotation on this class, and then any parent
- * classes.
- * <li><ck>[ClassName].license</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>license</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#license() @ResourceSwagger.license()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(license=<js>"{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(license=<js>"$C{MyStrings/MyClass.myLicenseInfo}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].license</ck>
+ * <li><ck>license</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#license() @ResourceSwagger.license()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.license</ck> = <cv>{name:"Apache 2.0",url:"http://www.apache.org/licenses/LICENSE-2.0.html"}</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.license</ck> = <cv>$C{MyStrings/MyClass.myLicenseInfo}</cv>
+ * </p>
* <li><ck>/info/license</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized license information of this REST resource, or <jk>null</jk> if none was found found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public License getLicense(RestRequest req) {
+ public License getLicense(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
JsonParser jp = JsonParser.DEFAULT;
try {
- if (this.license != null)
- return jp.parse(vr.resolve(this.license), License.class);
+ if (license != null)
+ return jp.parse(vr.resolve(license), License.class);
String license = context.getMessages().findFirstString(req.getLocale(), "license");
if (license != null)
return jp.parse(vr.resolve(license), License.class);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getLicense();
return null;
@@ -482,31 +1121,55 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own terms-of-service information.
*
* <p>
- * The default implementation returns the terms-of-service information from the following locations (whichever
- * matches first):
- * <ol>
- * <li>{@link ResourceSwagger#termsOfService() @ResourceSwagger.termsOfService()} annotation on this class, and
- * then any parent classes.
- * <li><ck>[ClassName].termsOfService</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>termsOfService</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#termsOfService() @ResourceSwagger.termsOfService()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(termsOfService=<js>"You're on your own"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(termsOfService=<js>"$C{MyStrings/MyClass.myTermsOfService}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].termsOfService</ck>
+ * <li><ck>termsOfService</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#termsOfService() @ResourceSwagger.termsOfService()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.termsOfService</ck> = <cv>You''re on your own</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.termsOfService</ck> = <cv>$C{MyStrings/MyClass.myTermsOfService}</cv>
+ * </p>
* <li><ck>/info/termsOfService</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized terms-of-service of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getTermsOfService(RestRequest req) {
+ public String getTermsOfService(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
- if (this.termsOfService != null)
- return vr.resolve(this.termsOfService);
+ if (termsOfService != null)
+ return vr.resolve(termsOfService);
String termsOfService = context.getMessages().findFirstString(req.getLocale(), "termsOfService");
if (termsOfService != null)
return vr.resolve(termsOfService);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getTermsOfService();
return null;
@@ -519,69 +1182,186 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own version information.
*
* <p>
- * The default implementation returns the version information from the following locations (whichever matches first):
- * <ol>
- * <li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
- * classes.
- * <li><ck>[ClassName].version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(version=<js>"2.0"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(version=<js>"$C{MyStrings/MyClass.myVersion}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].version</ck>
+ * <li><ck>version</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#version() @ResourceSwagger.version()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.version</ck> = <cv>2.0</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.version</ck> = <cv>$C{MyStrings/MyClass.myVersion}</cv>
+ * </p>
* <li><ck>/info/version</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized version of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public String getVersion(RestRequest req) {
+ public String getVersion(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
- if (this.version != null)
- return vr.resolve(this.version);
+ if (version != null)
+ return vr.resolve(version);
String version = context.getMessages().findFirstString(req.getLocale(), "version");
if (version != null)
return vr.resolve(version);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null && s.getInfo() != null)
return s.getInfo().getVersion();
return null;
}
/**
+ * Returns the supported <code>Content-Type</code> request headers for the REST resource.
+ * <p>
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(version=<js>"2.0"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(version=<js>"$C{MyStrings/MyClass.myVersion}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].version</ck>
+ * <li><ck>version</ck>
+ * </ol>
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#version() @ResourceSwagger.version()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.version</ck> = <cv>2.0</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.version</ck> = <cv>$C{MyStrings/MyClass.myVersion}</cv>
+ * </p>
+ * <li><ck>/info/version</ck> entry in swagger file.
+ * </ol>
+ *
+ * @param req The current request.
+ * @return
+ * The supported <code>Content-Type</code> request headers of the REST resource, or <jk>null</jk> if none were found.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public List<MediaType> getConsumes(RestRequest req) throws Exception {
+ List<MediaType> l = req.getContext().getConsumes();
+ return l.isEmpty() ? null : l;
+ }
+
+ /**
+ * Returns the supported <code>Accept</code> request headers for the REST resource.
+ *
+ * @param req The current request.
+ * @return
+ * The supported <code>Accept</code> request headers of the REST resource, or <jk>null</jk> if none were found.
+ * @throws Exception
+ */
+ @Override /* RestInfoProvider */
+ public List<MediaType> getProduces(RestRequest req) throws Exception {
+ List<MediaType> l = req.getContext().getProduces();
+ return l.isEmpty() ? null : l;
+ }
+
+ /**
* Returns the version information of this REST resource.
*
* <p>
* Subclasses can override this method to provide their own version information.
*
* <p>
- * The default implementation returns the version information from the following locations (whichever matches first):
- * <ol>
- * <li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
- * classes.
- * <li><ck>[ClassName].version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>/info/version</ck> entry in swagger file.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#tags() @ResourceSwagger.tags()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(tags=<js>"foo,bar,baz"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(tags=<js>"$C{MyStrings/MyClass.myTags}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].tags</ck>
+ * <li><ck>tags</ck>
+ * </ol>
+ * <br>Value is either a comma-delimited list or a JSON array.
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#tags() @ResourceSwagger.tags()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Comma-delimited list</cc>
+ * <ck>MyClass.tags</ck> = <cv>foo,bar,baz</cv>
+ *
+ * <cc>// JSON array</cc>
+ * <ck>MyClass.tags</ck> = <cv>["foo","bar","baz"]</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.tags</ck> = <cv>$C{MyStrings/MyClass.myTags}</cv>
+ * </p>
+ * <li><ck>tags</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized tags of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public List<Tag> getTags(RestRequest req) {
+ public List<Tag> getTags(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
JsonParser jp = JsonParser.DEFAULT;
try {
- if (this.tags != null)
- return jp.parse(vr.resolve(this.tags), ArrayList.class, Tag.class);
+ if (tags != null)
+ return jp.parse(vr.resolve(tags), ArrayList.class, Tag.class);
String tags = context.getMessages().findFirstString(req.getLocale(), "tags");
if (tags != null)
return jp.parse(vr.resolve(tags), ArrayList.class, Tag.class);
- Swagger s = req.getSwaggerFromFile();
- if (s != null)
+ Swagger s = getSwaggerFromFile(req);
+ if (s != null && s.getTags() != null)
return s.getTags();
return null;
} catch (Exception e) {
@@ -596,32 +1376,58 @@ public class RestInfoProviderDefault implements RestInfoProvider {
* Subclasses can override this method to provide their own version information.
*
* <p>
- * The default implementation returns the version information from the following locations (whichever matches first):
- * <ol>
- * <li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
- * classes.
- * <li><ck>[ClassName].version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>version</ck> property in resource bundle identified by
- * {@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
- * <li><ck>/info/version</ck> entry in swagger file.
+ * The default implementation returns the value from the following locations (whichever matches first):
+ * <ol class='spaced-list'>
+ * <li>{@link ResourceSwagger#externalDocs() @ResourceSwagger.externalDocs()} annotation on this class, and then any parent classes.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <jc>// Direct value</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(externalDocs=<js>"{url:'http://juneau.apache.org'}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ *
+ * <jc>// Pulled from some other location</jc>
+ * <ja>@RestResource</ja>(
+ * swagger=<ja>@ResourceSwagger</ja>(externalDocs=<js>"$C{MyStrings/MyClass.myExternalDocs}"</js>)
+ * )
+ * <jk>public class</jk> MyResource {...}
+ * </p>
+ * <li>Localized strings from resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+ * on the resource class, then any parent classes.
+ * <ol>
+ * <li><ck>[ClassName].externalDocs</ck>
+ * <li><ck>externalDocs</ck>
+ * </ol>
+ * <br>Value is a JSON objec representation of a {@link ExternalDocumentation} object.
+ * <br>Value can contain any SVL variables defined on the {@link ResourceSwagger#externalDocs() @ResourceSwagger.externalDocs()} annotation.
+ * <h6 class='figure'>Examples:</h6>
+ * <p class='bcode'>
+ * <cc>// Direct value</cc>
+ * <ck>MyClass.externalDocs</ck> = <cv>{url:"http://juneau.apache.org"}</cv>
+ *
+ * <cc>// Pulled from some other location</cc>
+ * <ck>MyClass.externalDocs</ck> = <cv>$C{MyStrings/MyClass.myExternalDocs}</cv>
+ * </p>
+ * <li><ck>externalDocs</ck> entry in swagger file.
* </ol>
*
* @param req The current request.
* @return
- * The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+ * The localized external documentation of this REST resource, or <jk>null</jk> if none was found.
+ * @throws Exception
*/
@Override /* RestInfoProvider */
- public ExternalDocumentation getExternalDocs(RestRequest req) {
+ public ExternalDocumentation getExternalDocs(RestRequest req) throws Exception {
VarResolverSession vr = req.getVarResolverSession();
JsonParser jp = JsonParser.DEFAULT;
try {
- if (this.externalDocs != null)
- return jp.parse(vr.resolve(this.externalDocs), ExternalDocumentation.class);
+ if (externalDocs != null)
+ return jp.parse(vr.resolve(externalDocs), ExternalDocumentation.class);
String externalDocs = context.getMessages().findFirstString(req.getLocale(), "externalDocs");
if (externalDocs != null)
return jp.parse(vr.resolve(externalDocs), ExternalDocumentation.class);
- Swagger s = req.getSwaggerFromFile();
+ Swagger s = getSwaggerFromFile(req);
if (s != null)
return s.getExternalDocs();
return null;
@@ -629,4 +1435,18 @@ public class RestInfoProviderDefault implements RestInfoProvider {
throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
}
}
+
+ private Operation getSwaggerOperationFromFile(Method method, RestRequest req) throws Exception {
+
+ Swagger s = getSwaggerFromFile(req);
+ if (s != null) {
+ Map<String,Map<String,Operation>> sp = s.getPaths();
+ if (sp != null) {
+ Map<String,Operation> spp = sp.get(method.getAnnotation(RestMethod.class).path());
+ if (spp != null)
+ return spp.get(req.getMethod());
+ }
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/juneau/blob/62b041ab/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
----------------------------------------------------------------------
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 b6ef494..b4d0b1d 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
@@ -14,7 +14,6 @@ package org.apache.juneau.rest;
import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.BeanContext.*;
-import static org.apache.juneau.dto.swagger.SwaggerBuilder.*;
import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.internal.Utils.*;
@@ -27,12 +26,10 @@ import java.util.*;
import javax.servlet.http.*;
import org.apache.juneau.*;
-import org.apache.juneau.dto.swagger.*;
import org.apache.juneau.encoders.*;
import org.apache.juneau.http.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.internal.*;
-import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.widget.*;
@@ -46,17 +43,13 @@ import org.apache.juneau.utils.*;
public class RestJavaMethod implements Comparable<RestJavaMethod> {
private final String httpMethod;
private final UrlPathPattern pathPattern;
- private final RestParam[] params;
+ final RestParam[] params;
private final RestGuard[] guards;
private final RestMatcher[] optionalMatchers;
private final RestMatcher[] requiredMatchers;
private final RestConverter[] converters;
private final RestMethodProperties properties;
- private final boolean deprecated;
- private final String description, tags, summary, externalDocs;
private final Integer priority;
- private final org.apache.juneau.rest.annotation.Parameter[] parameters;
- private final Response[] responses;
private final RestContext context;
final java.lang.reflect.Method method;
final SerializerGroup serializers;
@@ -99,21 +92,14 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
this.defaultFormData = b.defaultFormData;
this.defaultCharset = b.defaultCharset;
this.maxInput = b.maxInput;
- this.deprecated = b.deprecated;
- this.description = b.description;
- this.tags = b.tags;
- this.summary = b.summary;
- this.externalDocs = b.externalDocs;
this.priority = b.priority;
- this.parameters = b.parameters;
- this.responses = b.responses;
this.supportedAcceptTypes = b.supportedAcceptTypes;
this.supportedContentTypes = b.supportedContentTypes;
this.widgets = Collections.unmodifiableMap(b.widgets);
}
private static final class Builder {
- String httpMethod, defaultCharset, description, tags, summary, externalDocs;
+ String httpMethod, defaultCharset;
UrlPathPattern pathPattern;
RestParam[] params;
RestGuard[] guards;
@@ -127,11 +113,8 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
BeanContext beanContext;
RestMethodProperties properties;
Map<String,Object> defaultRequestHeaders, defaultQuery, defaultFormData;
- boolean deprecated;
long maxInput;
Integer priority;
- org.apache.juneau.rest.annotation.Parameter[] parameters;
- Response[] responses;
Map<String,Widget> widgets;
List<MediaType> supportedAcceptTypes, supportedContentTypes;
@@ -146,18 +129,6 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
VarResolver vr = context.getVarResolver();
- if (! m.description().isEmpty())
- description = m.description();
- MethodSwagger sm = m.swagger();
- if (! sm.tags().isEmpty())
- tags = sm.tags();
- if (! m.summary().isEmpty())
- summary = m.summary();
- if (! sm.externalDocs().isEmpty())
- externalDocs = sm.externalDocs();
- deprecated = sm.deprecated();
- parameters = sm.parameters();
- responses = sm.responses();
serializers = context.getSerializers();
parsers = context.getParsers();
partSerializer = context.getPartSerializer();
@@ -409,12 +380,12 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
beanContext = bcb.build();
supportedAcceptTypes =
- m.supportedAcceptTypes().length > 0
- ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.supportedAcceptTypes())))))
+ m.produces().length > 0
+ ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.produces())))))
: serializers.getSupportedMediaTypes();
supportedContentTypes =
- m.supportedContentTypes().length > 0
- ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.supportedContentTypes())))))
+ m.consumes().length > 0
+ ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.consumes())))))
: parsers.getSupportedMediaTypes();
params = context.findParams(method, pathPattern, false);
@@ -451,322 +422,6 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
}
/**
- * Returns the localized Swagger for this Java method.
- */
- Operation getSwaggerOperation(RestRequest req) throws ParseException {
- Operation o = operation()
- .operationId(method.getName())
- .description(getDescription(req))
- .tags(getTags(req))
- .summary(getSummary(req))
- .externalDocs(getExternalDocs(req))
- .parameters(getParameters(req))
- .responses(getResponses(req));
-
- if (isDeprecated())
- o.deprecated(true);
-
- if (! parsers.getSupportedMediaTypes().equals(context.getParsers().getSupportedMediaTypes()))
- o.consumes(parsers.getSupportedMediaTypes());
-
- if (! serializers.getSupportedMediaTypes().equals(context.getSerializers().getSupportedMediaTypes()))
- o.produces(serializers.getSupportedMediaTypes());
-
- return o;
- }
-
- private Operation getSwaggerOperationFromFile(RestRequest req) {
- Swagger s = req.getSwaggerFromFile();
- if (s != null && s.getPaths() != null && s.getPaths().get(pathPattern.getPatternString()) != null)
- return s.getPaths().get(pathPattern.getPatternString()).get(httpMethod);
- return null;
- }
-
- /**
- * Returns the localized summary for this Java method.
- */
- String getSummary(RestRequest req) {
- VarResolverSession vr = req.getVarResolverSession();
- if (summary != null)
- return vr.resolve(summary);
- String summary = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".summary");
- if (summary != null)
- return vr.resolve(summary);
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null)
- return o.getSummary();
- return null;
- }
-
- /**
- * Returns the localized description for this Java method.
- */
- String getDescription(RestRequest req) {
- VarResolverSession vr = req.getVarResolverSession();
- if (description != null)
- return vr.resolve(description);
- String description = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".description");
- if (description != null)
- return vr.resolve(description);
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null)
- return o.getDescription();
- return null;
- }
-
- /**
- * Returns the localized Swagger tags for this Java method.
- */
- private List<String> getTags(RestRequest req) {
- VarResolverSession vr = req.getVarResolverSession();
- JsonParser jp = JsonParser.DEFAULT;
- try {
- if (tags != null)
- return jp.parse(vr.resolve(tags), ArrayList.class, String.class);
- String tags = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".tags");
- if (tags != null)
- return jp.parse(vr.resolve(tags), ArrayList.class, String.class);
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null)
- return o.getTags();
- return null;
- } catch (Exception e) {
- throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
- }
- }
-
- /**
- * Returns the localized Swagger external docs for this Java method.
- */
- private ExternalDocumentation getExternalDocs(RestRequest req) {
- VarResolverSession vr = req.getVarResolverSession();
- JsonParser jp = JsonParser.DEFAULT;
- try {
- if (externalDocs != null)
- return jp.parse(vr.resolve(externalDocs), ExternalDocumentation.class);
- String externalDocs = context.getMessages().findFirstString(req.getLocale(), method.getName() + ".externalDocs");
- if (externalDocs != null)
- return jp.parse(vr.resolve(externalDocs), ExternalDocumentation.class);
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null)
- return o.getExternalDocs();
- return null;
- } catch (Exception e) {
- throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
- }
- }
-
- /**
- * Returns the Swagger deprecated flag for this Java method.
- */
- private boolean isDeprecated() {
- return deprecated;
- }
-
- /**
- * Returns the localized Swagger parameter information for this Java method.
- */
- private List<ParameterInfo> getParameters(RestRequest req) throws ParseException {
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null && o.getParameters() != null)
- return o.getParameters();
-
- VarResolverSession vr = req.getVarResolverSession();
- JsonParser jp = JsonParser.DEFAULT;
- Map<String,ParameterInfo> m = new TreeMap<>();
-
- // First parse @RestMethod.parameters() annotation.
- for (org.apache.juneau.rest.annotation.Parameter v : parameters) {
- String in = vr.resolve(v.in());
- ParameterInfo p = parameterInfo(in, vr.resolve(v.name()));
-
- if (! v.description().isEmpty())
- p.description(vr.resolve(v.description()));
- if (v.required())
- p.required(v.required());
-
- if ("body".equals(in)) {
- if (! v.schema().isEmpty())
- p.schema(jp.parse(vr.resolve(v.schema()), SchemaInfo.class));
- } else {
- if (v.allowEmptyValue())
- p.allowEmptyValue(v.allowEmptyValue());
- if (! v.collectionFormat().isEmpty())
- p.collectionFormat(vr.resolve(v.collectionFormat()));
- if (! v._default().isEmpty())
- p._default(vr.resolve(v._default()));
- if (! v.format().isEmpty())
- p.format(vr.resolve(v.format()));
- if (! v.items().isEmpty())
- p.items(jp.parse(vr.resolve(v.items()), Items.class));
- p.type(vr.resolve(v.type()));
- }
- m.put(p.getIn() + '.' + p.getName(), p);
- }
-
- // Next, look in resource bundle.
- String prefix = method.getName() + ".req";
- for (String key : context.getMessages().keySet(prefix)) {
- if (key.length() > prefix.length()) {
- String value = vr.resolve(context.getMessages().getString(key));
- String[] parts = key.substring(prefix.length() + 1).split("\\.");
- String in = parts[0], name, field;
- boolean isBody = "body".equals(in);
- if (parts.length == (isBody ? 2 : 3)) {
- if ("body".equals(in)) {
- name = null;
- field = parts[1];
- } else {
- name = parts[1];
- field = parts[2];
- }
- String k2 = in + '.' + name;
- ParameterInfo p = m.get(k2);
- if (p == null) {
- p = parameterInfoStrict(in, name);
- m.put(k2, p);
- }
-
- if (field.equals("description"))
- p.description(value);
- else if (field.equals("required"))
- p.required(Boolean.valueOf(value));
-
- if ("body".equals(in)) {
- if (field.equals("schema"))
- p.schema(jp.parse(value, SchemaInfo.class));
- } else {
- if (field.equals("allowEmptyValue"))
- p.allowEmptyValue(Boolean.valueOf(value));
- else if (field.equals("collectionFormat"))
- p.collectionFormat(value);
- else if (field.equals("default"))
- p._default(value);
- else if (field.equals("format"))
- p.format(value);
- else if (field.equals("items"))
- p.items(jp.parse(value, Items.class));
- else if (field.equals("type"))
- p.type(value);
- }
- } else {
- System.err.println("Unknown bundle key '"+key+"'");
- }
- }
- }
-
- // Finally, look for parameters defined on method.
- for (RestParam mp : this.params) {
- RestParamType in = mp.getParamType();
- if (in != RestParamType.OTHER) {
- String k2 = in.toString() + '.' + (in == RestParamType.BODY ? null : mp.getName());
- ParameterInfo p = m.get(k2);
- if (p == null) {
- p = parameterInfoStrict(in.toString(), mp.getName());
- m.put(k2, p);
- }
- }
- }
-
- if (m.isEmpty())
- return null;
- return new ArrayList<>(m.values());
- }
-
- /**
- * Returns the localized Swagger response information about this Java method.
- */
- private Map<Integer,ResponseInfo> getResponses(RestRequest req) throws ParseException {
- Operation o = getSwaggerOperationFromFile(req);
- if (o != null && o.getResponses() != null)
- return o.getResponses();
-
- VarResolverSession vr = req.getVarResolverSession();
- JsonParser jp = JsonParser.DEFAULT;
- Map<Integer,ResponseInfo> m = new TreeMap<>();
- Map<String,HeaderInfo> m2 = new TreeMap<>();
-
- // First parse @RestMethod.parameters() annotation.
- for (Response r : responses) {
- int httpCode = r.value();
- String description = r.description().isEmpty() ? RestUtils.getHttpResponseText(r.value()) : vr.resolve(r.description());
- ResponseInfo r2 = responseInfo(description);
-
- if (r.headers().length > 0) {
- for (org.apache.juneau.rest.annotation.Parameter v : r.headers()) {
- HeaderInfo h = headerInfoStrict(vr.resolve(v.type()));
- if (! v.collectionFormat().isEmpty())
- h.collectionFormat(vr.resolve(v.collectionFormat()));
- if (! v._default().isEmpty())
- h._default(vr.resolve(v._default()));
- if (! v.description().isEmpty())
- h.description(vr.resolve(v.description()));
- if (! v.format().isEmpty())
- h.format(vr.resolve(v.format()));
- if (! v.items().isEmpty())
- h.items(jp.parse(vr.resolve(v.items()), Items.class));
- r2.header(v.name(), h);
- m2.put(httpCode + '.' + v.name(), h);
- }
- }
- m.put(httpCode, r2);
- }
-
- // Next, look in resource bundle.
- String prefix = method.getName() + ".res";
- for (String key : context.getMessages().keySet(prefix)) {
- if (key.length() > prefix.length()) {
- String value = vr.resolve(context.getMessages().getString(key));
- String[] parts = key.substring(prefix.length() + 1).split("\\.");
- int httpCode = Integer.parseInt(parts[0]);
- ResponseInfo r2 = m.get(httpCode);
- if (r2 == null) {
- r2 = responseInfo(null);
- m.put(httpCode, r2);
- }
-
- String name = parts.length > 1 ? parts[1] : "";
-
- if ("header".equals(name) && parts.length > 3) {
- String headerName = parts[2];
- String field = parts[3];
-
- String k2 = httpCode + '.' + headerName;
- HeaderInfo h = m2.get(k2);
- if (h == null) {
- h = headerInfoStrict("string");
- m2.put(k2, h);
- r2.header(name, h);
- }
- if (field.equals("collectionFormat"))
- h.collectionFormat(value);
- else if (field.equals("default"))
- h._default(value);
- else if (field.equals("description"))
- h.description(value);
- else if (field.equals("format"))
- h.format(value);
- else if (field.equals("items"))
- h.items(jp.parse(value, Items.class));
- else if (field.equals("type"))
- h.type(value);
-
- } else if ("description".equals(name)) {
- r2.description(value);
- } else if ("schema".equals(name)) {
- r2.schema(jp.parse(value, SchemaInfo.class));
- } else if ("examples".equals(name)) {
- r2.examples(jp.parse(value, TreeMap.class));
- } else {
- System.err.println("Unknown bundle key '"+key+"'");
- }
- }
- }
-
- return m.isEmpty() ? null : m;
- }
-
- /**
* Returns <jk>true</jk> if the specified request object can call this method.
*/
boolean isRequestAllowed(RestRequest req) {
@@ -795,7 +450,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
remainder = patternVals[pathPattern.getVars().length];
for (int i = 0; i < pathPattern.getVars().length; i++)
req.getPathMatch().put(pathPattern.getVars()[i], patternVals[i]);
- req.getPathMatch().setRemainder(remainder);
+ req.getPathMatch().pattern(pathPattern.getPatternString()).remainder(remainder);
RestRequestProperties requestProperties = new RestRequestProperties(req.getVarResolverSession(), properties);