http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Parameter.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Parameter.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Parameter.java new file mode 100644 index 0000000..6b88277 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Parameter.java @@ -0,0 +1,180 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation used in conjunction with {@link RestMethod#parameters()} to identify content and header descriptions + * on specific method requests. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"*"</js>, + * parameters={ + * <ja>@Parameter</ja>(in=<js>"header"</js>, name=<js>"Range"</js>, description=<js>"$L{ContentRange.description}"</js>) + * } + * ) + * <jk>public void</jk> doAnything(RestRequest req, RestResponse res, <ja>@Method</ja> String method) { + * ... + * } + * </p> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Parameter { + + /** + * The location of the parameter. + * <p> + * Possible values are: + * <ul> + * <li><js>"query"</js> + * <li><js>"header"</js> + * <li><js>"path"</js> + * <li><js>"formData"</js> + * <li><js>"body"</js> + * </ul> + */ + String in() default ""; + + /** + * The name of the parameter (e.g. <js>"Content-Range"</js>). + * <p> + * Parameter names are case sensitive. + * If <code>in</code> is <js>"path"</js>, the name field MUST correspond to the associated path segment from the <code>path</code> field in the <a href='http://swagger.io/specification/#pathsObject'>Paths Object</a>. + * See <a href='http://swagger.io/specification/#pathTemplating'>Path Templating</a> for further information. + * For all other cases, the name corresponds to the parameter name used based on the <code>in</code> property. + */ + String name() default ""; + + /** + * Parameter description (e.g. <js>"Indicates the range returned when Range header is present in the request"</js>). + * <p> + * A brief description of the parameter. + * This could contain examples of use. + * <a href='https://help.github.com/articles/github-flavored-markdown'>GFM syntax</a> can be used for rich text representation. + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code].[category].[name] = foo"</js> or <js>"MyServlet.myMethod.res.[code].[category].[name] = foo"</js>). + */ + String description() default ""; + + /** + * Determines whether this parameter is mandatory. + * <p> + * If the parameter is <code>in</code> <js>"path"</js>, this property is required and its value MUST be <jk>true</jk>. + * Otherwise, the property MAY be included and its default value is <jk>false</jk>. + */ + boolean required() default false; + + /** + * The schema defining the type used for the body parameter. + * <p> + * Only applicable for <code>in</code> of type <js>"body"</js>. + * <p> + * The schema is a JSON object specified <a href='http://swagger.io/specification/#schemaObject'>here</a>. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * parameters={ + * <ja>@Parameter</ja>( + * in=<js>"header"</js>, + * name=<js>"Foo"</js>, + * schema=<js>"{format:'string',title:'Foo header',description:'Header that contains the Foo value.'}"</js>) + * } + * ) + * <jk>public void</jk> doAnything() { + * </p> + */ + String schema() default ""; + + /** + * The type of the parameter. + * <p> + * The value MUST be one of <js>"string"</js>, <js>"number"</js>, <js>"integer"</js>, <js>"boolean"</js>, <js>"array"</js> or <js>"file"</js>. + * If type is <js>"file"</js>, the consumes MUST be either <js>"multipart/form-data"</js>, <js>"application/x-www-form-urlencoded"</js> or both and the parameter MUST be in <js>"formData"</js>. + */ + String type() default "string"; + + /** + * The extending format for the previously mentioned <code>type</code>. + * <p> + * See <a href='http://swagger.io/specification/#dataTypeFormat'>Data Type Formats</a> for further details. + */ + String format() default ""; + + /** + * Sets the ability to pass empty-valued parameters. + * <p> + * This is valid only for either <code>query</code> or <code>formData</code> parameters and allows you to send a parameter with a name only or an empty value. + * Default value is <jk>false</jk>. + */ + boolean allowEmptyValue() default false; + + /** + * Required if <code>type</code> is <js>"array"</js>. + * <p> + * Describes the type of items in the array. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * parameters={ + * <ja>@Parameter</ja>( + * in=<js>"header"</js>, + * name=<js>"Foo"</js>, + * type=<js>"array"</js>, + * items=<js>"{type:'string',collectionFormat:'csv'}"</js>) + * } + * ) + * <jk>public void</jk> doAnything() { + * </p> + * <p> + * See <a href='http://swagger.io/specification/#itemsObject'>Items Object</a> for further details. + */ + String items() default ""; + + /** + * Determines the format of the array if type array is used. + * <p> + * Possible values are: + * <ul> + * <li><js>"csv"</js> - comma separated values <js>"foo,bar"</js>. + * <li><js>"ssv"</js> - space separated values <js>"foo bar"</js>. + * <li><js>"tsv"</js> - tab separated values <js>"foo\tbar"</js>. + * <li><js>"pipes"</js> - pipe separated values <js>"foo|bar"</js>. + * <li><js>"multi"</js> - corresponds to multiple parameter instances instead of multiple values for a single instance <js>"foo=bar&foo=baz"</js>. + * This is valid only for parameters <code>in</code> <js>"query"</js> or <js>"formData"</js>. + * </ul> + * Default value is <js>"csv"</js>. + */ + String collectionFormat() default ""; + + /** + * Declares the value of the parameter that the server will use if none is provided. + * <p> + * For example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. + * (Note: "default" has no meaning for required parameters.) + * See <a href='http://json-schema.org/latest/json-schema-validation.html#anchor101'>http://json-schema.org/latest/json-schema-validation.html#anchor101</a>. + * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for this parameter. + */ + String _default() default ""; +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Path.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Path.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Path.java new file mode 100644 index 0000000..e64ccf3 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Path.java @@ -0,0 +1,72 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method + * to identify it as a variable in a URL path pattern converted to a POJO. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res, + * <ja>@Path</ja> String foo, <ja>@Path</ja> <jk>int</jk> bar, <ja>@Path</ja> UUID baz) { + * ... + * } + * </p> + * <p> + * The <ja>@Path</ja> annotation is optional if the parameters are specified immediately + * following the <code>RestRequest</code> and <code>RestResponse</code> parameters, + * and are specified in the same order as the variables in the URL path pattern. + * The following example is equivalent to the previous example. + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res, + * String foo, <jk>int</jk> bar, UUID baz) { + * ... + * } + * </p> + * <p> + * If the order of parameters is not the default order shown above, the + * attribute names must be specified (since parameter names are lost during compilation). + * The following example is equivalent to the previous example, except + * the parameter order has been switched, requiring the use of the <ja>@Path</ja> + * annotations. + * <p> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res, + * <ja>@Path</ja>(<js>"baz"</js>) UUID baz, <ja>@Path</ja>(<js>"foo"</js>) String foo, <ja>@Path</ja>(<js>"bar"</js>) <jk>int</jk> bar) { + * ... + * } + * </p> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Path { + + /** + * URL variable name. + * <p> + * Optional if the attributes are specified in the same order as in the URL path pattern. + */ + String value() default ""; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/PathRemainder.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/PathRemainder.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/PathRemainder.java new file mode 100644 index 0000000..728fde0 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/PathRemainder.java @@ -0,0 +1,46 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method + * to identify it as the URL parameter remainder after a path pattern match. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/*"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res, <ja>@PathRemainder</ja> String remainder) { + * ... + * } + * </p> + * <p> + * This is functionally equivalent to the following code... + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/*"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res) { + * String remainder = req.getPathRemainder(); + * ... + * } + * </p> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface PathRemainder {} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Properties.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Properties.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Properties.java new file mode 100644 index 0000000..a70e908 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Properties.java @@ -0,0 +1,64 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.*; + +/** + * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method + * to identify the request-duration properties object for the current request. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>) + * <jk>public Person</jk> doGetPerson(<ja>@Properties</ja> ObjectMap properties) { + * properties.put(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>); + * ... + * } + * </p> + * <p> + * This is functionally equivalent to the following code... + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>) + * <jk>public Person</jk> doGetPerson(RestResponse res) { + * ObjectMap properties = res.getProperties(); + * properties.put(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>); + * ... + * } + * </p> + * <p> + * ...or this... + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>) + * <jk>public Person</jk> doGetPerson(RestResponse res) { + * res.setProperty(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>); + * ... + * } + * </p> + * <p> + * The parameter type can be one of the following: + * <ul> + * <li>{@link ObjectMap} + * <li><code>Map<String,Object></code> + * </ul> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Properties {} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Property.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Property.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Property.java new file mode 100644 index 0000000..a4a8344 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Property.java @@ -0,0 +1,63 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.*; +import org.apache.juneau.jena.*; +import org.apache.juneau.json.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.xml.*; + +/** + * Property name/value pair used in the {@link RestResource#properties()} annotation. + * <p> + * Any of the following property names can be specified: + * <ul> + * <li>{@link BeanContext} + * <li>{@link SerializerContext} + * <li>{@link ParserContext} + * <li>{@link JsonSerializerContext} + * <li>{@link RdfSerializerContext} + * <li>{@link RdfParserContext} + * <li>{@link RdfCommonContext} + * <li>{@link XmlSerializerContext} + * <li>{@link XmlParserContext} + * </ul> + * <p> + * Property values types that are not <code>Strings</code> will automatically be converted to the + * correct type (e.g. <code>Boolean</code>, etc...). + * <p> + * See {@link RestResource#properties} for more information. + */ +@Documented +@Target(ANNOTATION_TYPE) +@Retention(RUNTIME) +@Inherited +public @interface Property { + + /** + * Property name. + */ + String name(); + + /** + * Property value. + */ + String value(); +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java new file mode 100644 index 0000000..42cb4b0 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java @@ -0,0 +1,92 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.rest.*; + +/** + * Identical to {@link FormData @FormData}, but only retrieves the parameter from the + * URL string, not URL-encoded form posts. + * <p> + * Unlike {@link FormData @FormData}, using this annotation does not result in the servlet reading the contents + * of URL-encoded form posts. + * Therefore, this annotation can be used in conjunction with the {@link Body @Body} annotation + * or {@link RestRequest#getBody(Class)} method for <code>application/x-www-form-urlencoded POST</code> calls. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res, + * <ja>@Query</ja>(<js>"p1"</js>) <jk>int</jk> p1, <ja>@Query</ja>(<js>"p2"</js>) String p2, <ja>@Query</ja>(<js>"p3"</js>) UUID p3) { + * ... + * } + * </p> + * <p> + * This is functionally equivalent to the following code... + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res) { + * <jk>int</jk> p1 = req.getQueryParameter(<jk>int</jk>.<jk>class</jk>, <js>"p1"</js>, 0); + * String p2 = req.getQueryParameter(String.<jk>class</jk>, <js>"p2"</js>); + * UUID p3 = req.getQueryParameter(UUID.<jk>class</jk>, <js>"p3"</js>); + * ... + * } + * </p> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Query { + + /** + * URL parameter name. + */ + String value(); + + /** + * Specify <jk>true</jk> if using multi-part parameters to represent collections and arrays. + * <p> + * Normally, we expect single parameters to be specified in UON notation for representing + * collections of values (e.g. <js>"&key=(1,2,3)"</js>. + * This annotation allows the use of multi-part parameters to represent collections + * (e.g. <js>"&key=1&key=2&key=3"</js>. + * <p> + * This setting should only be applied to Java parameters of type array or Collection. + */ + boolean multipart() default false; + + /** + * The expected format of the request parameter. + * <p> + * Possible values: + * <ul class='spaced-list'> + * <li><js>"UON"</js> - URL-Encoded Object Notation.<br> + * This notation allows for request parameters to contain arbitrarily complex POJOs. + * <li><js>"PLAIN"</js> - Plain text.<br> + * This treats request parameters as plain text.<br> + * Only POJOs directly convertable from <l>Strings</l> can be represented in parameters when using this mode. + * <li><js>"INHERIT"</js> (default) - Inherit from the {@link RestServletContext#REST_paramFormat} property on the servlet method or class. + * </ul> + * <p> + * Note that the parameter value <js>"(foo)"</js> is interpreted as <js>"(foo)"</js> when using plain mode, but + * <js>"foo"</js> when using UON mode. + */ + String format() default "INHERIT"; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Response.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Response.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Response.java new file mode 100644 index 0000000..6cc7860 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Response.java @@ -0,0 +1,87 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation used in conjunction with {@link RestMethod#responses()} to identify possible responses by the method. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"*"</js>, + * responses={ + * <ja>@Response</ja>(value=200,description=<js>"Everything was great."</js>), + * <ja>@Response</ja>(value=404,description=<js>"File was not found."</js>) + * <ja>@Response</ja>(500), + * } + * ) + * <jk>public void</jk> doAnything(RestRequest req, RestResponse res, <ja>@Method</ja> String method) { + * ... + * } + * </p> + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Response { + + /** + * HTTP response code. + */ + int value(); + + /** + * Optional description. + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code].description = foo"</js> or <js>"MyServlet.myMethod.res.[code].description = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/responses/{code}/description</code>. + */ + String description() default ""; + + /** + * A definition of the response structure. + * <p> + * It can be a primitive, an array or an object. + * If this field does not exist, it means no content is returned as part of the response. + * As an extension to the <a href='http://swagger.io/specification/#schemaObject'>Schema Object</a>, its root type value may also be <js>"file"</js>. + * This SHOULD be accompanied by a relevant produces mime-type. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"*"</js>, + * responses={ + * <ja>@Response</ja>(value=200,schema=<js>"{type:'string',description:'A serialized Person bean.'}"</js>), + * } + * </p> + */ + String schema() default ""; + + /** + * Optional response headers. + * <p> + * Response variables can also be defined in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code].[category].[name] = foo"</js> or <js>"MyServlet.myMethod.res.[code].[category].[name] = foo"</js>). + */ + Parameter[] headers() default {}; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java new file mode 100644 index 0000000..1dc75e9 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java @@ -0,0 +1,505 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.encoders.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.serializer.*; + +/** + * Identifies a REST Java method on a {@link RestServlet} implementation class. + * <p> + * Refer to {@link org.apache.juneau.rest} doc for information on using this class. + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +@Inherited +public @interface RestMethod { + + /** + * REST method name. + * <p> + * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>. + * <p> + * Can also be a non-HTTP-standard name that is passed in through a <code>&method=methodName</code> URL parameter. + * <p> + * Method names are case-insensitive (always folded to upper-case). + * <p> + * If a method name is not specified, then the method name is determined based on the Java method name.<br> + * For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected as <js>"POST"</js>. + + */ + String name() default ""; + + /** + * Optional path pattern for the specified method. + * <p> + * Appending <js>"/*"</js> to the end of the path pattern will make it match any remainder too.<br> + * Not appending <js>"/*"</js> to the end of the pattern will cause a 404 (Not found) error to occur + * if the exact pattern is not found. + */ + String path() default "/*"; + + /** + * URL path pattern priority. + * <p> + * To force path patterns to be checked before other path patterns, use a higher priority number. + * <p> + * By default, it's <code>0</code>, which means it will use an internal heuristic to + * determine a best match. + */ + int priority() default 0; + + /** + * Method guards. + * <p> + * Associates one or more {@link RestGuard RestGuards} with a method call. + * These guards get called immediately before execution of the REST method. + * <p> + * Typically, guards will be used for permissions checking on the user making the request, + * but it can also be used for other purposes like pre-call validation of a request. + */ + Class<? extends RestGuard>[] guards() default {}; + + /** + * Method response converters. + * <p> + * Associates one or more {@link RestConverter RestConverters} with a method call. + * These converters get called immediately after execution of the REST method in the same + * order specified in the annotation. + * <p> + * Can be used for performing post-processing on the response object before serialization. + * <p> + * Default converters are available in the {@link org.apache.juneau.rest.converters} package. + */ + Class<? extends RestConverter>[] converters() default {}; + + /** + * Method matchers. + * <p> + * Associates one more more {@link RestMatcher RestMatchers} with this method. + * <p> + * Matchers are used to allow multiple Java methods to handle requests assigned to the same + * URL path pattern, but differing based on some request attribute, such as a specific header value. + * <p> + * See {@link RestMatcher} for details. + */ + Class<? extends RestMatcher>[] matchers() default {}; + + /** + * Overrides the list of serializers assigned at the method level. + * <p> + * Use this annotation when the list of serializers assigned to a method differs from the list of serializers assigned at the servlet level. + * <p> + * To append to the list of serializers assigned at the servlet level, use <code>serializersInherit=<jsf>SERIALIZERS</jsf></code>. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"GET"</js>, + * path=<js>"/foo"</js>, + * serializers=MySpecialSerializer.<jk>class</jk>, + * serializersInherit=<jsf>SERIALIZERS</jsf> + * ) + * <jk>public</jk> Object doGetWithSpecialAcceptType() { + * <jc>// Handle request for special Accept type</jc> + * } + * } + * </p> + */ + Class<? extends Serializer>[] serializers() default {}; + + /** + * Used in conjunction with {@link #serializers()} to identify what class-level settings are inherited by the method serializer group. + * <p> + * Possible values: + * <ul> + * <li>{@link Inherit#SERIALIZERS} - Inherit class-level serializers. + * <li>{@link Inherit#PROPERTIES} - Inherit class-level properties. + * <li>{@link Inherit#TRANSFORMS} - Inherit class-level transforms. + * </ul> + * <p> + * For example, to inherit all serializers, properties, and transforms from the servlet class: + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * path=<js>"/foo"</js>, + * serializers=MySpecialSerializer.<jk>class</jk>, + * serializersInherit={<jsf>SERIALIZERS</jsf>,<jsf>PROPERTIES</jsf>,<jsf>TRANSFORMS</jsf>} + * ) + * </p> + */ + Inherit[] serializersInherit() default {}; + + /** + * Overrides the list of parsers assigned at the method level. + * <p> + * Use this annotation when the list of parsers assigned to a method differs from the list of parsers assigned at the servlet level. + * <p> + * To append to the list of serializers assigned at the servlet level, use <code>serializersInherit=<jsf>SERIALIZERS</jsf></code>. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"PUT"</js>, + * path=<js>"/foo"</js>, + * parsers=MySpecialParser.<jk>class</jk>, + * parsersInherit=<jsf>PARSERS</jsf> + * ) + * <jk>public</jk> Object doGetWithSpecialAcceptType() { + * <jc>// Handle request for special Accept type</jc> + * } + * } + * </p> + */ + Class<? extends Parser>[] parsers() default {}; + + /** + * Used in conjunction with {@link #parsers()} to identify what class-level settings are inherited by the method parser group. + * <p> + * Possible values: + * <ul> + * <li>{@link Inherit#PARSERS} - Inherit class-level parsers. + * <li>{@link Inherit#PROPERTIES} - Inherit class-level properties. + * <li>{@link Inherit#TRANSFORMS} - Inherit class-level transforms. + * </ul> + * <p> + * For example, to inherit all parsers, properties, and transforms from the servlet class: + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * path=<js>"/foo"</js>, + * parsers=MySpecialParser.<jk>class</jk>, + * parsersInherit={<jsf>PARSERS</jsf>,<jsf>PROPERTIES</jsf>,<jsf>TRANSFORMS</jsf>} + * ) + * </p> + */ + Inherit[] parsersInherit() default {}; + + /** + * Appends to the list of {@link Encoder encoders} specified on the servlet. + * <p> + * Use this annotation when the list of encoders assigned to a method differs from the list of encoders assigned at the servlet level. + * <p> + * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"PUT"</js>, + * path=<js>"/foo"</js>, + * encoders={GzipEncoder.<jk>class</jk>} + * ) + * <jk>public</jk> Object doGetWithSpecialEncoding() { + * <jc>// Handle request with special encoding</jc> + * } + * } + * </p> + * <p> + * If you want to OVERRIDE the set of encoders specified by the servlet, combine this annotation with <code><ja>@RestMethod</ja>(inheritEncoders=<jk>false</jk>)</code>. + */ + Class<? extends Encoder>[] encoders() default {}; + + /** + * Specifies whether the method should inherit encoders from the servlet. + */ + boolean inheritEncoders() default true; + + /** + * Same as {@link RestResource#properties()}, except defines property values by default when this method is called. + * <p> + * This is equivalent to simply calling <code>res.addProperties()</code> in the Java method, but is provided for convenience. + */ + Property[] properties() default {}; + + /** + * Appends the specified bean filters to all serializers and parsers used by this method. + */ + Class<?>[] beanFilters() default {}; + + /** + * Appends the specified POJO swaps to all serializers and parsers used by this method. + */ + Class<?>[] pojoSwaps() default {}; + + /** + * Specifies default values for request headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request. + * <p> + * The most useful reason for this annotation is to provide a default <code>Accept</code> header when one is not specified + * so that a particular default {@link Serializer} is picked. + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * <p> + * Header values specified at the method level override header values specified at the servlet level. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jc>// Assume "text/json" Accept value when Accept not specified</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>, defaultRequestHeaders={<js>"Accept: text/json"</js>}) + * <jk>public</jk> String doGet() { + * ... + * } + * </p> + */ + String[] defaultRequestHeaders() default {}; + + /** + * Optional summary for the exposed API. + * <p> + * This summary is used in the following locations: + * <ul class='spaced-list'> + * <li>The value returned by {@link RestRequest#getMethodSummary()}. + * <li>The <js>"$R{methodSummary}"</js> variable. + * <li>The summary of the method in the Swagger page. + * </ul> + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName].summary</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod.summary = foo"</js> or <js>"myMethod.summary = foo"</js>). + * <p> + * This field value can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/summary</code>. + */ + String summary() default ""; + + /** + * Optional description for the exposed API. + * <p> + * This description is used in the following locations: + * <ul class='spaced-list'> + * <li>The value returned by {@link RestRequest#getMethodDescription()}. + * <li>The <js>"$R{methodDescription}"</js> variable. + * <li>The description of the method in the Swagger page. + * </ul> + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName].description</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod.description = foo"</js> or <js>"myMethod.description = foo"</js>). + * <p> + * This field value can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/description</code>. + */ + String description() default ""; + + /** + * Optional external documentation information for the exposed API. + * <p> + * Used to populate the Swagger external documentation field. + * <p> + * A simplified JSON string with the following fields: + * <p class='bcode'> + * { + * description: string, + * url: string + * } + * </p> + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName].externalDocs</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod.externalDocs = {url:'http://juneau.apache.org'}"</js> or <js>"myMethod.externalDocs = {url:'http://juneau.apache.org'}"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(externalDocs=<js>"{url:'http://juneau.apache.org'}"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/externalDocs</code>. + */ + String externalDocs() default ""; + + /** + * Optional tagging information for the exposed API. + * <p> + * Used to populate the Swagger tags field. + * <p> + * A comma-delimited list of tags for API documentation control. + * Tags can be used for logical grouping of operations by resources or any other qualifier. + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName].tags</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod.tags = foo,bar"</js> or <js>"myMethod.tags = foo,bar"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(tags=<js>"foo,bar"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/tags</code>. + */ + String tags() default ""; + + /** + * Optional deprecated flag for the exposed API. + * <p> + * Used to populate the Swagger deprecated field. + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName].deprecated</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod.deprecated = true"</js> or <js>"myMethod.deprecated = foo,bar"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>(deprecated=<jk>true</jk>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/deprecated</code>. + */ + boolean deprecated() default false; + + /** + * Optional parameter descriptions. + * <p> + * This annotation is provided for documentation purposes and is used to populate the method <js>"parameters"</js> column + * on the Swagger page. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"POST"</js>, path=<js>"/{a}"</js>, + * description=<js>"This is my method."</js>, + * parameters={ + * <ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"a"</js>, description=<js>"The 'a' attribute"</js>), + * <ja>@Parameter</ja>(in=<js>"query"</js>, name=<js>"b"</js>, description=<js>"The 'b' parameter"</js>, required=<jk>true</jk>), + * <ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"The HTTP content"</js>), + * <ja>@Parameter</ja>(in=<js>"header"</js>, name=<js>"D"</js>, description=<js>"The 'D' header"</js>), + * } + * ) + * </p> + * This is functionally equivalent to specifying the following keys in the resource bundle for the class, except in this case + * the strings are internationalized. + * <p class='bcode'> + * <jk>MyClass.myMethod.description</jk> = <js>This is my method.</js> + * <jk>MyClass.myMethod.req.path.a.description</jk> = <js>The 'a' attribute</js> + * <jk>MyClass.myMethod.req.query.b.description</jk> = <js>The 'b' parameter</js> + * <jk>MyClass.myMethod.req.body.description</jk> = <js>The HTTP content</js> + * <jk>MyClass.myMethod.req.header.d.description</jk> = <js>The 'D' header</js> + * <p> + * As a general rule, use annotations when you don't care about internationalization (i.e. you only want to support English), + * and use resource bundles if you need to support localization. + * <p> + * These annotations can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/paths/{path}/{method}/parameters</code>. + */ + Parameter[] parameters() default {}; + + /** + * Optional output description. + * <p> + * This annotation is provided for documentation purposes and is used to populate the method <js>"responses"</js> column + * on the Swagger page. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"GET"</js>, path=<js>"/"</js>, + * responses={ + * <ja>@Response</ja>(200), + * <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>) + * } + * ) + * } + * ) + * </p> + * This is functionally equivalent to specifying the following keys in the resource bundle for the class, except in this case + * the strings are internationalized. + * <p class='bcode'> + * <jk>MyClass.myMethod.res.200.description</jk> = <js>OK</js> + * <jk>MyClass.myMethod.res.302.description</jk> = <js>Thing wasn't found here</js> + * <jk>MyClass.myMethod.res.302.header.Location.description</jk> = <js>The place to find the thing</js> + * <p> + * As a general rule, use annotations when you don't care about internationalization (i.e. you only want to support English), + * and use resource bundles if you need to support localization. + * <p> + * These annotations can contain variables (e.g. "$L{my.localized.variable}"). + */ + Response[] responses() default {}; + + /** + * Specifies whether this method can be called based on the client version. + * <p> + * The client version is identified via the HTTP request header identified by {@link RestResource#clientVersionHeader()} which + * by default is <js>"X-Client-Version"</js>. + * <p> + * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same method/path based + * on the client version. + * <p> + * The format of the client version range is similar to that of OSGi versions. + * <p> + * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>. + * <p class='bcode'> + * <jc>// Call this method if X-Client-Version is at least 2.0. + * // Note that this also matches 2.0.1.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>) + * <jk>public</jk> Object method1() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>) + * <jk>public</jk> Object method2() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is less than 1.1.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>) + * <jk>public</jk> Object method3() { + * ... + * } + * </p> + * <p> + * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for backwards compatability. + * <p class='bcode'> + * <jc>// Call this method if X-Client-Version is at least 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>) + * <jk>public</jk> NewPojo newMethod() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>, transforms={NewToOldPojoSwap.<jk>class</jk>}) + * <jk>public</jk> NewPojo oldMethod() { + * <jk>return</jk> newMethod() + * } + * <p> + * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into an older form. + * The old method could also just return back a completely different object. + * The range can be any of the following: + * <ul> + * <li><js>"[0,1.0)"</js> = Less than 1.0. 1.0 and 1.0.0 does not match. + * <li><js>"[0,1.0]"</js> = Less than or equal to 1.0. Note that 1.0.1 will match. + * <li><js>"1.0"</js> = At least 1.0. 1.0 and 2.0 will match. + * </ul> + */ + String clientVersion() default ""; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java new file mode 100644 index 0000000..1948ce0 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java @@ -0,0 +1,592 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import javax.servlet.http.*; + +import org.apache.juneau.*; +import org.apache.juneau.encoders.*; +import org.apache.juneau.jena.*; +import org.apache.juneau.json.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.transform.*; +import org.apache.juneau.utils.*; +import org.apache.juneau.xml.*; + +/** + * Optionally used to associate metadata on an instance of {@link RestServlet}. + * <p> + * Refer to {@link org.apache.juneau.rest} doc for information on using this class. + */ +@Documented +@Target(TYPE) +@Retention(RUNTIME) +@Inherited +public @interface RestResource { + + /** + * Identifies the location of the resource bundle for this class. + * <p> + * This annotation is used to provide localized messages for the following methods: + * <ul> + * <li>{@link RestServlet#getMessage(java.util.Locale, String, Object...)} + * <li>{@link RestServlet#getTitle(RestRequest)} + * <li>{@link RestServlet#getDescription(RestRequest)} + * </ul> + * <p> + * Refer to the {@link MessageBundle} class for a description of the message key formats + * used in the properties file. + * <p> + * The value can be a relative path like <js>"nls/Messages"</js>, indicating to look for the + * resource bundle <js>"com.foo.sample.nls.Messages"</js> if the resource class + * is in <js>"com.foo.sample"</js>, or it can be an absolute path, like <js>"com.foo.sample.nls.Messages"</js> + */ + String messages() default ""; + + /** + * Class-level guards. + * <p> + * Associates one or more {@link RestGuard RestGuards} with all REST methods defined + * in this class. + * These guards get called immediately before execution of any REST method in this class. + * <p> + * Typically, guards will be used for permissions checking on the user making the request, + * but it can also be used for other purposes like pre-call validation of a request. + */ + Class<? extends RestGuard>[] guards() default {}; + + /** + * Class-level converters. + * <p> + * Associates one or more {@link RestConverter converters} with a resource class. + * These converters get called immediately after execution of the REST method in the same + * order specified in the annotation. + * <p> + * Can be used for performing post-processing on the response object before serialization. + * <p> + * Default converter implementations are provided in the {@link org.apache.juneau.rest.converters} package. + */ + Class<? extends RestConverter>[] converters() default {}; + + /** + * Class-level bean filters. + * <p> + * Shortcut to add bean filters to the bean contexts of the objects returned by the following methods: + * <ul> + * <li>{@link RestServlet#getBeanContext()} + * <li>{@link RestServlet#getSerializers()} + * <li>{@link RestServlet#getParsers()} + * </ul> + * <p> + * If the specified class is an instance of {@link BeanFilterBuilder}, then a filter built from that builder is added. + * Any other classes are wrapped in a {@link InterfaceBeanFilterBuilder} to indicate that subclasses should + * be treated as the specified class type. + */ + Class<?>[] beanFilters() default {}; + + /** + * Class-level POJO swaps. + * <p> + * Shortcut to add POJO swaps to the bean contexts of the objects returned by the following methods: + * <ul> + * <li>{@link RestServlet#getBeanContext()} + * <li>{@link RestServlet#getSerializers()} + * <li>{@link RestServlet#getParsers()} + * </ul> + * <p> + * If the specified class is an instance of {@link PojoSwap}, then that swap is added. + * Any other classes are wrapped in a {@link SurrogateSwap}. + */ + Class<?>[] pojoSwaps() default {}; + + /** + * Class-level properties. + * <p> + * Shortcut for specifying class-level properties on this servlet to the objects returned by the following methods: + * <ul> + * <li>{@link RestServlet#getBeanContext()} + * <li>{@link RestServlet#getSerializers()} + * <li>{@link RestServlet#getParsers()} + * </ul> + * <p> + * Any of the following property names can be specified: + * <ul> + * <li>{@link RestServletContext} + * <li>{@link BeanContext} + * <li>{@link SerializerContext} + * <li>{@link ParserContext} + * <li>{@link JsonSerializerContext} + * <li>{@link RdfSerializerContext} + * <li>{@link RdfParserContext} + * <li>{@link RdfCommonContext} + * <li>{@link XmlSerializerContext} + * <li>{@link XmlParserContext} + * </ul> + * <p> + * Property values will be converted to the appropriate type. + * <p> + * In some cases, properties can be overridden at runtime through the {@link RestResponse#setProperty(String, Object)} method + * or through a {@link Properties @Properties} annotated method parameter. + */ + Property[] properties() default {}; + + /** + * Specifies a list of {@link Serializer} classes to add to the list of serializers available for this servlet. + * <p> + * This annotation can only be used on {@link Serializer} classes that have no-arg constructors. + */ + Class<? extends Serializer>[] serializers() default {}; + + /** + * Specifies a list of {@link Parser} classes to add to the list of parsers available for this servlet. + * <p> + * This annotation can only be used on {@link Parser} classes that have no-arg constructors. + */ + Class<? extends Parser>[] parsers() default {}; + + /** + * Specifies a list of {@link ResponseHandler} classes that know how to convert POJOs returned + * by REST methods or set via {@link RestResponse#setOutput(Object)} into appropriate + * HTTP responses. + * <p> + * See {@link ResponseHandler} for details. + */ + Class<? extends ResponseHandler>[] responseHandlers() default {}; + + /** + * Specifies a list of {@link Encoder} to associate with this servlet. + * <p> + * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses. + * <p> + * This annotation can only be used on {@link Encoder} classes that have no-arg constructors. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jc>// Servlet with automated support for GZIP compression</jc> + * <ja>@RestResource</ja>(encoders={GzipEncoder.<jk>class</jk>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + */ + Class<? extends Encoder>[] encoders() default {}; + + /** + * Specifies default values for request headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request. + * <p> + * The most useful reason for this annotation is to provide a default <code>Accept</code> header when one is not specified + * so that a particular default {@link Serializer} is picked. + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jc>// Assume "text/json" Accept value when Accept not specified</jc> + * <ja>@RestResource</ja>(defaultRequestHeaders={<js>"Accept: text/json"</js>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + */ + String[] defaultRequestHeaders() default {}; + + /** + * Specifies default values for response headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * This is equivalent to calling {@link RestResponse#setHeader(String, String)} programmatically in each of the Java methods. + * <p> + * The header value will not be set if the header value has already been specified (hence the 'default' in the name). + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jc>// Add a version header attribute to all responses</jc> + * <ja>@RestResource</ja>(defaultResponseHeaders={<js>"X-Version: 1.0"</js>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + */ + String[] defaultResponseHeaders() default {}; + + /** + * Defines children of this resource. + * <p> + * A REST child resource is simply another servlet that is initialized as part of the parent + * resource and has a servlet path directly under the parent servlet path. + * The main advantage to defining servlets as REST children is that you do not need + * to define them in the <code>web.xml</code> file of the web application. + * This can cut down on the number of entries that show up in the <code>web.xml</code> file + * if you are defining large numbers of servlets. + * <p> + * Child resources must specify a value for {@link #path()} that identifies the subpath of the + * child resource relative to the parent path. + * <p> + * It should be noted that servlets can be nested arbitrarily deep using this technique (i.e. children can also have children). + * + * <dl> + * <dt>Servlet initialization:</dt> + * <dd> + * <p> + * A child resource will be initialized immediately after the parent servlet is initialized. The child resource + * receives the same servlet config as the parent resource. This allows configuration information such as + * servlet initialization parameters to filter to child resources. + * </p> + * </dd> + * <dt>Runtime behavior:</dt> + * <dd> + * <p> + * As a rule, methods defined on the <code>HttpServletRequest</code> object will behave as if + * the child servlet were deployed as a top-level resource under the child's servlet path. + * For example, the <code>getServletPath()</code> and <code>getPathInfo()</code> methods on the + * <code>HttpServletRequest</code> object will behave as if the child resource were deployed + * using the child's servlet path. + * Therefore, the runtime behavior should be equivalent to deploying the child servlet in + * the <code>web.xml</code> file of the web application. + * </p> + * </dd> + * </dl> + */ + Class<?>[] children() default {}; + + /** + * Identifies the URL subpath relative to the parent resource. + * <p> + * Typically, this annotation is only applicable to resources defined as children through the {@link #children()} + * annotation. However, it may be used in other ways (e.g. defining paths for top-level resources in microservices). + * <p> + * This annotation is ignored on top-level servlets (i.e. servlets defined in <code>web.xml</code> files). + * Therefore, implementers can optionally specify a path value for documentation purposes. + */ + String path() default ""; + + /** + * Optional servlet title. + * <p> + * It is used to populate the Swagger title field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getTitle(RestRequest)} method. + * <p> + * The default value pulls the label from the <code>label</code> entry in the servlet resource bundle. + * (e.g. <js>"title = foo"</js> or <js>"MyServlet.title = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/title</code>. + */ + String title() default ""; + + /** + * Optional servlet description. + * <p> + * It is used to populate the Swagger description field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getDescription(RestRequest)} method. + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"description = foo"</js> or <js>"MyServlet.description = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/description</code>. + */ + String description() default ""; + + /** + * Optional servlet terms-of-service for this API. + * <p> + * It is used to populate the Swagger terms-of-service field. + * This value can be retrieved programmatically through the {@link RestServlet#getTermsOfService(RestRequest)} method. + * <p> + * The default value pulls the description from the <code>termsOfService</code> entry in the servlet resource bundle. + * (e.g. <js>"termsOfService = foo"</js> or <js>"MyServlet.termsOfService = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/termsOfService</code>. + */ + String termsOfService() default ""; + + /** + * Optional contact information for the exposed API. + * <p> + * It is used to populate the Swagger contact field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getContact(RestRequest)} method. + * <p> + * A simplified JSON string with the following fields: + * <p class='bcode'> + * { + * name: string, + * url: string, + * email: string + * } + * </p> + * <p> + * The default value pulls the description from the <code>contact</code> entry in the servlet resource bundle. + * (e.g. <js>"contact = {name:'John Smith',email:'john.sm...@foo.bar'}"</js> or <js>"MyServlet.contact = {name:'John Smith',email:'john.sm...@foo.bar'}"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestResource</ja>(contact=<js>"{name:'John Smith',email:'john.sm...@foo.bar'}"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/contact</code>. + */ + String contact() default ""; + + /** + * Optional license information for the exposed API. + * <p> + * It is used to populate the Swagger license field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getLicense(RestRequest)} method. + * <p> + * A simplified JSON string with the following fields: + * <p class='bcode'> + * { + * name: string, + * url: string + * } + * </p> + * <p> + * The default value pulls the description from the <code>license</code> entry in the servlet resource bundle. + * (e.g. <js>"license = {name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js> or <js>"MyServlet.license = {name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestResource</ja>(license=<js>"{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/license</code>. + */ + String license() default ""; + + /** + * Provides the version of the application API (not to be confused with the specification version). + * <p> + * It is used to populate the Swagger version field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getVersion(RestRequest)} method. + * <p> + * The default value pulls the description from the <code>version</code> entry in the servlet resource bundle. + * (e.g. <js>"version = 2.0"</js> or <js>"MyServlet.version = 2.0"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/info/version</code>. + */ + String version() default ""; + + /** + * Optional tagging information for the exposed API. + * <p> + * It is used to populate the Swagger tags field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getTags(RestRequest)} method. + * <p> + * A simplified JSON string with the following fields: + * <p class='bcode'> + * [ + * { + * name: string, + * description: string, + * externalDocs: { + * description: string, + * url: string + * } + * } + * ] + * </p> + * <p> + * The default value pulls the description from the <code>tags</code> entry in the servlet resource bundle. + * (e.g. <js>"tags = [{name:'Foo',description:'Foobar'}]"</js> or <js>"MyServlet.tags = [{name:'Foo',description:'Foobar'}]"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestResource</ja>(tags=<js>"[{name:'Foo',description:'Foobar'}]"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/tags</code>. + */ + String tags() default ""; + + /** + * Optional external documentation information for the exposed API. + * <p> + * It is used to populate the Swagger external documentation field and to display on HTML pages. + * This value can be retrieved programmatically through the {@link RestServlet#getExternalDocs(RestRequest)} method. + * <p> + * A simplified JSON string with the following fields: + * <p class='bcode'> + * { + * description: string, + * url: string + * } + * </p> + * <p> + * The default value pulls the description from the <code>externalDocs</code> entry in the servlet resource bundle. + * (e.g. <js>"externalDocs = {url:'http://juneau.apache.org'}"</js> or <js>"MyServlet.externalDocs = {url:'http://juneau.apache.org'}"</js>). + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <ja>@RestResource</ja>(externalDocs=<js>"{url:'http://juneau.apache.org'}"</js>) + * </p> + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + * <p> + * Corresponds to the swagger field <code>/tags</code>. + */ + String externalDocs() default ""; + + /** + * Optional location of configuration file for this servlet. + * <p> + * The configuration file . + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + */ + String config() default ""; + + /** + * The stylesheet to use for HTML views. + * <p> + * The name is a path to a stylesheet located in either the classpath or working directory. + * The resulting stylesheet becomes available through the servlet via the URL <js>"[servletpath]/style.css"</js>. + * <p> + * The default set of styles located in the <code>org.apache.juneau.rest.styles</code> package are: + * <ul class='spaced-list'> + * <li><js>"styles/juneau.css"</js> - Theme based on Jazz look-and-feel. + * <li><js>"styles/devops.css"</js> - Theme based on IBM DevOps look-and-feel. + * </ul> + * <p> + * The classpath search starts with the child servlet class and proceeds up the class hierarchy + * chain. Since the {@link RestServlet} class is in the <code>org.apache.juneau.rest</code> package + * and the predefined styles are in the <code>org.apache.juneau.rest.styles</code> package, the paths to + * the predefined styles are prefixed with <js>"styles/"</js>. + * <p> + * If the stylesheet cannot be found on the classpath, an attempt to look in the working directory + * for it will be made. This allows for stylesheets to be placed on the file system in the working + * directory. + * <p> + * If the file cannot be located, the request to <js>"[servletpath]/style.css"</js> will return {@link HttpServletResponse#SC_NOT_FOUND}. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jk>package</jk> com.foo.mypackage; + * + * <ja>@RestResource</ja>( + * stylesheet=<js>"mystyles/mycss.css"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, the servlet will attempt to find the <code>mycss.css</code> file in the following ordered locations: + * </p> + * <ol> + * <li><code>com.foo.mypackage.mystyles</code> package. + * <li><code>org.apache.juneau.rest.mystyles</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.rest</code>). + * <li><code>[working-dir]/mystyles</code> directory. + * </ol> + */ + String stylesheet() default ""; + + /** + * The favicon to use for HTML views. + * <p> + * The name is a path to an icon file located in either the classpath or working directory in a similar way + * to how the {@link #stylesheet()} stylesheet is resolved. + * The resulting favicon becomes available in the servlet via the URL <js>"[servletpath]/favicon.ico"</js>. + * <p> + * If the file cannot be located, the request to <js>"[servletpath]/favicon.ico"</js> will return {@link HttpServletResponse#SC_NOT_FOUND}. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jk>package</jk> com.foo.mypackage; + * + * <ja>@RestResource</ja>( + * favicon=<js>"mydocs/myicon.ico"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, the servlet will attempt to find the <code>myicon.ico</code> file in the following ordered locations: + * </p> + * <ol> + * <li><code>com.foo.mypackage.mydocs</code> package. + * <li><code>org.apache.juneau.rest.mydocs</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.rest</code>). + * <li><code>[working-dir]/mydocs</code> directory. + * </ol> + */ + String favicon() default ""; + + /** + * Defines paths and locations of statically served files. + * <p> + * This is a JSON map of paths to packages/directories located on either the classpath or working directory. + * <p> + * Mappings are cumulative from parent to child. Child resources can override mappings made on parent resources. + * <p> + * If the file cannot be located, the request will return {@link HttpServletResponse#SC_NOT_FOUND}. + * <p> + * The media type on the response is determined by the {@link RestServlet#getMimetypesFileTypeMap()} method. + * + * <h6 class='topic'>Example:</h6> + * <p class='bcode'> + * <jk>package</jk> com.foo.mypackage; + * + * <ja>@RestResource</ja>( + * path=<js>"/myresource"</js>, + * staticFiles=<js>"{htdocs:'docs'}"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, given a GET request to <code>/myresource/htdocs/foobar.html</code>, the servlet will attempt to find the <code>foobar.html</code> file + * in the following ordered locations: + * </p> + * <ol> + * <li><code>com.foo.mypackage.docs</code> package. + * <li><code>org.apache.juneau.rest.docs</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.rest</code>). + * <li><code>[working-dir]/docs</code> directory. + * </ol> + */ + String staticFiles() default ""; + + /** + * Specifies the HTTP header name used to identify the client version. + * <p> + * The client version is used to support backwards compatibility for breaking REST interface + * changes. Used in conjunction with {@link RestMethod#clientVersion()} annotation. + * <p> + * If not specified, uses <js>"X-Client-Version"</js>. + */ + String clientVersionHeader() default ""; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/package.html ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/package.html b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/package.html new file mode 100644 index 0000000..c0c0d41 --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/package.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + ***************************************************************************************************************************/ + --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>REST servlet annotations</p> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/91a388d0/juneau-rest/src/main/java/org/apache/juneau/rest/converters/Introspectable.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/converters/Introspectable.java b/juneau-rest/src/main/java/org/apache/juneau/rest/converters/Introspectable.java new file mode 100644 index 0000000..daa556e --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/converters/Introspectable.java @@ -0,0 +1,59 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.rest.converters; + +import static javax.servlet.http.HttpServletResponse.*; + +import org.apache.juneau.*; +import org.apache.juneau.json.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.utils.*; + +/** + * Converter for enablement of {@link PojoIntrospector} support on response objects returned by a <code>@RestMethod</code> method. + * <p> + * When enabled, public methods can be called on objects returned through the {@link RestResponse#setOutput(Object)} method. + * <p> + * Note that opening up public methods for calling through a REST interface can be dangerous, and should + * be done with caution. + * <p> + * Java methods are invoked by passing in the following URL parameters: + * <ul class='spaced-list'> + * <li><code>&invokeMethod</code> - The Java method name, optionally with arguments if necessary to differentiate between methods. + * <li><code>&invokeArgs</code> - The arguments as a JSON array. + * </ul> + * <p> + * See {@link PojoIntrospector} for additional information on introspecting POJO methods. + */ +public final class Introspectable implements RestConverter { + + @Override /* RestConverter */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object convert(RestRequest req, Object o, ClassMeta cm) throws RestException { + String method = req.getQueryParameter("invokeMethod"); + String args = req.getQueryParameter("invokeArgs"); + if (method == null) + return o; + try { + if (cm.getPojoSwap() != null) + o = cm.getPojoSwap().swap(req.getBeanSession(), o); + return new PojoIntrospector(o, JsonParser.DEFAULT).invokeMethod(method, args); + } catch (Exception e) { + e.printStackTrace(); + return new RestException(SC_INTERNAL_SERVER_ERROR, + "Error occurred trying to invoke method: {0}", + e.getLocalizedMessage() + ).initCause(e); + } + } +}