001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.http.remote; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.io.*; 023import java.lang.annotation.*; 024 025import org.apache.juneau.commons.*; 026import org.apache.juneau.http.*; 027 028/** 029 * Annotation applied to Java methods on REST proxy interface classes. 030 * 031 * <p> 032 * Note that this annotation is optional if you do not need to override any of the values. 033 * 034 * <h5 class='section'>See Also:</h5><ul> 035 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxies">REST Proxies</a> 036 * </ul> 037 */ 038@Documented 039@Target(METHOD) 040@Retention(RUNTIME) 041@Inherited 042@AnnotationGroup(RemoteOp.class) 043public @interface RemoteOp { 044 045 /** 046 * Defines the HTTP method to use for REST calls. 047 * 048 * <p> 049 * If not specified, then the method is inferred from the Java method name. 050 * 051 * <h5 class='figure'>Example:</h5> 052 * <p class='bjava'> 053 * <ja>@RemotePost</ja> 054 * <jk>public void</jk> postPet(...); 055 * </p> 056 * 057 * <br>If the method cannot be inferred, then the default is <js>"GET"</js>. 058 * 059 * <p> 060 * Note that you can also use {@link #value()} to specify the method name and path in shortened form. 061 * 062 * @return The annotation value. 063 */ 064 String method() default ""; 065 066 /** 067 * REST service path. 068 * 069 * <p> 070 * If you do not specify a path, then the path is inferred from the Java method name. 071 * 072 * <h5 class='figure'>Example:</h5> 073 * <p class='bjava'> 074 * <ja>@RemotePost</ja> 075 * <jk>public void</jk> postPet(...); 076 * </p> 077 * 078 * <p> 079 * Note that you can also use {@link #value()} to specify the method name and path in shortened form. 080 * 081 * <ul class='values'> 082 * <li>An absolute URL. 083 * <li>A relative URL interpreted as relative to the root URL defined on the <c>RestClient</c> and/or {@link Remote#path()}. 084 * <li>No path. 085 * </ul> 086 * 087 * @return The annotation value. 088 */ 089 String path() default ""; 090 091 /** 092 * The value the remote method returns. 093 * 094 * <ul class='values'> 095 * <li> 096 * {@link RemoteReturn#BODY} (default) - The body of the HTTP response converted to a POJO. 097 * <br>The return type on the Java method can be any of the following: 098 * <ul class='spaced-list'> 099 * <li> 100 * <jk>void</jk> - Don't parse any response. Note that the method will still throw an exception if an 101 * error HTTP status is returned. 102 * <li> 103 * Any parsable POJO - The body of the response will be converted to the POJO using the parser defined 104 * on the <c>RestClient</c>. 105 * <li> 106 * Any POJO annotated with the {@link Response @Response} annotation. 107 * This allows for response beans to be used which also allows for OpenAPI-based parsing and validation. 108 * <li> 109 * <c>HttpResponse</c> - Returns the raw <c>HttpResponse</c> returned by the inner 110 * <c>HttpClient</c>. 111 * <li> 112 * {@link Reader} - Returns access to the raw reader of the response. 113 * <li> 114 * {@link InputStream} - Returns access to the raw input stream of the response. 115 * </ul> 116 * <li> 117 * {@link RemoteReturn#STATUS} - The HTTP status code on the response. 118 * <br>The return type on the Java method can be any of the following: 119 * <ul> 120 * <li><jk>int</jk>/<c>Integer</c> - The HTTP response code. 121 * <li><jk>boolean</jk>/<c>Boolean</c> - <jk>true</jk> if the response code is <c><400</c> 122 * </ul> 123 * </ul> 124 * 125 * @return The annotation value. 126 */ 127 RemoteReturn returns() default RemoteReturn.BODY; 128 129 /** 130 * REST method name and path. 131 * 132 * <p> 133 * Can be used to provide a shortened combined form for the {@link #method()} and {@link #path()} values. 134 * 135 * <p> 136 * The following examples are considered equivalent. 137 * <p class='bjava'> 138 * <jc>// Normal form</jc> 139 * <ja>@RemoteOp</ja>(method=<jsf>PUT</jsf>, path=<js>"/{propertyName}"</js>) 140 * 141 * <jc>// Shortened form</jc> 142 * <ja>@RemoteOp</ja>(<js>"PUT /{propertyName}"</js>) 143 * </p> 144 * 145 * <h5 class='section'>Notes:</h5><ul> 146 * <li class='note'> 147 * The path portion is optional. 148 * </ul> 149 * 150 * @return The annotation value. 151 */ 152 String value() default ""; 153 154 /** 155 * Base/host override applied to this method's request. 156 * 157 * <p> 158 * Replaces only the authority+root portion of the request URL while <i>preserving</i> the interface base path, this 159 * method's path, and any <c>{var}</c> templating. For example, with <c>baseUrl=<js>"http://other-host"</js></c>, an 160 * interface path of <js>"/api"</js> and a method path of <js>"/users/{id}"</js>, the effective URL is 161 * <js>"http://other-host/api/users/{id}"</js>. 162 * 163 * <p> 164 * Precedence (most-specific first): an {@link Url @Url} parameter, then this method-level 165 * value, then the interface-level default ({@link Remote#baseUrl()}), then the client root URL. 166 * 167 * <h5 class='section'>Notes:</h5><ul> 168 * <li class='note'> 169 * Supports <a class="doclink" href="https://juneau.apache.org/docs/topics/DefaultVarResolver">VarResolver.DEFAULT</a> 170 * (e.g. <js>"$S{mySystemProperty}"</js>). 171 * <li class='note'> 172 * Only <c>http</c>/<c>https</c> schemes are permitted when the override yields an absolute URL; other schemes 173 * are rejected (SSRF guardrail). 174 * <li class='note'> 175 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 176 * (<c>RestClient.getRemote(...)</c>), with the same http/https-only scheme guard on both. 177 * </ul> 178 * 179 * @return The annotation value. 180 */ 181 String baseUrl() default ""; 182 183 /** 184 * Selects the request body format (and the {@code Content-Type} header) for this method's request. 185 * 186 * <p> 187 * Names a media type (e.g. <js>"application/xml"</js>). The next-generation engine selects the matching registered 188 * request serializer from the client's serializer set so the request body bytes are actually written in that 189 * format, and sets the {@code Content-Type} header to this media type — cleanly replacing the serializer's 190 * default content type (exactly one {@code Content-Type} header is sent). 191 * 192 * <p> 193 * If no registered serializer matches this media type, the client's default serializer is used to write the body 194 * but this media type is still sent as the {@code Content-Type} label (supporting vendor media types such as 195 * <js>"application/vnd.example.v2+json"</js> whose bytes are really the default format). 196 * 197 * <p> 198 * Precedence (most-specific first): this method-level value, then the interface-level default 199 * ({@link Remote#contentType()}). This dedicated attribute takes precedence over a constant {@code Content-Type} 200 * declared via {@link #headers()} (since it also drives serializer selection); a genuinely caller-supplied 201 * {@code @Header("Content-Type")} parameter still takes effect. 202 * 203 * <h5 class='section'>Notes:</h5><ul> 204 * <li class='note'> 205 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 206 * (<c>RestClient.getRemote(...)</c>). 207 * </ul> 208 * 209 * @return The annotation value. 210 */ 211 String contentType() default ""; 212 213 /** 214 * Sets the {@code Accept} header (and the response parser fallback) for this method's request. 215 * 216 * <p> 217 * Names a media type (e.g. <js>"application/xml"</js>) sent as the request's {@code Accept} header. Response 218 * parsing remains driven by the <i>response</i> {@code Content-Type} (the server is authoritative about what it 219 * actually sent); this media type is used as the fallback parser only when the response is unlabeled or its 220 * {@code Content-Type} matches no registered parser. 221 * 222 * <p> 223 * If no registered parser matches this media type, the client's default parser is used as the fallback. 224 * 225 * <p> 226 * Precedence (most-specific first): this method-level value, then the interface-level default 227 * ({@link Remote#accept()}). This dedicated attribute takes precedence over a constant {@code Accept} declared via 228 * {@link #headers()}; a genuinely caller-supplied {@code @Header("Accept")} parameter still takes effect. Exactly 229 * one {@code Accept} header is sent. 230 * 231 * <h5 class='section'>Notes:</h5><ul> 232 * <li class='note'> 233 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 234 * (<c>RestClient.getRemote(...)</c>). 235 * </ul> 236 * 237 * @return The annotation value. 238 */ 239 String accept() default ""; 240 241 /** 242 * Constant request headers applied to every invocation of this method. 243 * 244 * <p> 245 * Each entry uses the <js>"Name: value"</js> form (the first <js>':'</js> separates name from value), mirroring 246 * {@link Remote#headers()}. The header is emitted unconditionally on every call — no corresponding method 247 * parameter is required. A caller-supplied parameter value for the same name still composes with the constant 248 * (it is not suppressed), and this method-level value takes precedence over an interface-level 249 * {@link Remote#headers()} constant of the same name. 250 * 251 * <h5 class='section'>Notes:</h5><ul> 252 * <li class='note'> 253 * Supports <a class="doclink" href="https://juneau.apache.org/docs/topics/DefaultVarResolver">VarResolver.DEFAULT</a> 254 * (e.g. <js>"$S{mySystemProperty}"</js>). 255 * <li class='note'> 256 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 257 * (<c>RestClient.getRemote(...)</c>). 258 * </ul> 259 * 260 * @return The annotation value. 261 */ 262 String[] headers() default {}; 263 264 /** 265 * Constant request query parameters applied to every invocation of this method. 266 * 267 * <p> 268 * Each entry uses the <js>"name=value"</js> form (the first <js>'='</js> separates name from value). The query 269 * parameter is emitted unconditionally on every call — no corresponding method parameter is required. A 270 * caller-supplied parameter value for the same name still composes with the constant (it is not suppressed), and 271 * this method-level value takes precedence over an interface-level {@link Remote#queryData()} constant of the same 272 * name. 273 * 274 * <h5 class='section'>Notes:</h5><ul> 275 * <li class='note'> 276 * Supports <a class="doclink" href="https://juneau.apache.org/docs/topics/DefaultVarResolver">VarResolver.DEFAULT</a> 277 * (e.g. <js>"$S{mySystemProperty}"</js>). 278 * <li class='note'> 279 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 280 * (<c>RestClient.getRemote(...)</c>). 281 * </ul> 282 * 283 * @return The annotation value. 284 */ 285 String[] queryData() default {}; 286 287 /** 288 * Constant request form-data parameters applied to every invocation of this method. 289 * 290 * <p> 291 * Each entry uses the <js>"name=value"</js> form (the first <js>'='</js> separates name from value). The form-data 292 * field is emitted unconditionally on every call — no corresponding method parameter is required. A 293 * caller-supplied parameter value for the same name still composes with the constant (it is not suppressed), and 294 * this method-level value takes precedence over an interface-level {@link Remote#formData()} constant of the same 295 * name. 296 * 297 * <h5 class='section'>Notes:</h5><ul> 298 * <li class='note'> 299 * Supports <a class="doclink" href="https://juneau.apache.org/docs/topics/DefaultVarResolver">VarResolver.DEFAULT</a> 300 * (e.g. <js>"$S{mySystemProperty}"</js>). 301 * <li class='note'> 302 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 303 * (<c>RestClient.getRemote(...)</c>). 304 * </ul> 305 * 306 * @return The annotation value. 307 */ 308 String[] formData() default {}; 309 310 /** 311 * Lifecycle interceptors applied to every invocation of this method. 312 * 313 * <p> 314 * Each class must implement the next-generation <c>RestCallInterceptor</c> SPI and provide a public no-arg 315 * constructor. Method-level interceptors run <i>after</i> (closest to the call) any interface-level 316 * ({@link Remote#interceptors()}) and builder-configured interceptors; the three sets are unioned in the order 317 * builder → interface → method. 318 * 319 * <h5 class='section'>Notes:</h5><ul> 320 * <li class='note'> 321 * The member type is {@code Class<?>[]} (not {@code Class<? extends RestCallInterceptor>[]}) because 322 * <c>RestCallInterceptor</c> lives in the {@code juneau-rest-client} module, which this annotation's module 323 * must not depend on; each element is resolved to a <c>RestCallInterceptor</c> at proxy-build time. 324 * <li class='note'> 325 * Honored by the next-generation engine (<c>RestClient.remote(...)</c>) only; the classic engine currently 326 * ignores this attribute. 327 * </ul> 328 * 329 * @return The annotation value. 330 */ 331 Class<?>[] interceptors() default {}; 332 333 /** 334 * Per-call response/read timeout applied to this method's request. 335 * 336 * <p> 337 * Expressed as a duration string (e.g. <js>"30s"</js>, <js>"1500ms"</js>, <js>"1m"</js>) parsed by Juneau's 338 * duration parser, and wired to the underlying transport's response timeout. Scalar precedence: this method-level 339 * value overrides the interface-level default ({@link Remote#timeout()}). Connect timeouts remain a client-level 340 * setting. 341 * 342 * <h5 class='section'>Notes:</h5><ul> 343 * <li class='note'> 344 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 345 * (<c>RestClient.getRemote(...)</c>). 346 * </ul> 347 * 348 * @return The annotation value. 349 */ 350 String timeout() default ""; 351 352 /** 353 * Maximum number of automatic retry attempts for this method's request. 354 * 355 * <p> 356 * A value of {@code 0} (the default) disables retries. Retries are attempted only on connection failures and on 357 * retryable HTTP statuses ({@code 429} and {@code 5xx}), with a short exponential backoff between attempts. 358 * 359 * <p> 360 * <b>Safety gating (hard rules):</b> 361 * <ul> 362 * <li>Auto-retry applies only to idempotent verbs (<c>GET</c>/<c>PUT</c>/<c>DELETE</c>/<c>HEAD</c>); non-idempotent 363 * verbs (<c>POST</c>/<c>PATCH</c>) are retried only when {@link #retryNonIdempotent()} is <jk>true</jk>. 364 * <li>A request whose body is not repeatable (e.g. a streaming {@link InputStream}/{@link Reader} 365 * body) is never retried. 366 * <li>Retries are disabled for streaming return modes ({@link RemoteReturn#RESPONSE}, raw 367 * {@link InputStream}/{@link Reader} returns, and streaming cursors) and for 368 * {@link java.util.concurrent.Future}/{@link java.util.concurrent.CompletableFuture} returns. 369 * </ul> 370 * 371 * <p> 372 * Scalar precedence: a positive method-level value overrides the interface-level default ({@link Remote#retries()}). 373 * 374 * <h5 class='section'>Notes:</h5><ul> 375 * <li class='note'> 376 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 377 * (<c>RestClient.getRemote(...)</c>). 378 * </ul> 379 * 380 * @return The annotation value. 381 */ 382 int retries() default 0; 383 384 /** 385 * Opts a non-idempotent verb (<c>POST</c>/<c>PATCH</c>) into automatic retries. 386 * 387 * <p> 388 * Has no effect unless {@link #retries()} (or {@link Remote#retries()}) is positive. Even when enabled, a request 389 * with a non-repeatable body is never retried. The effective value is the logical OR of this method-level value 390 * and the interface-level default ({@link Remote#retryNonIdempotent()}). 391 * 392 * <h5 class='section'>Notes:</h5><ul> 393 * <li class='note'> 394 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 395 * (<c>RestClient.getRemote(...)</c>). 396 * </ul> 397 * 398 * @return The annotation value. 399 */ 400 boolean retryNonIdempotent() default false; 401 402 /** 403 * Throws a generic exception when the response status is an error ({@code >=400}) and no typed exception from the 404 * method's {@code throws} clause matched. 405 * 406 * <p> 407 * Composes with the typed-exception mapping: a declared exception type whose status code matches the response is 408 * still thrown in preference to the generic exception. Respects the same return-mode gating as the typed mapping. 409 * The effective value is the logical OR of this method-level value and the interface-level default 410 * ({@link Remote#throwOnError()}). 411 * 412 * <h5 class='section'>Notes:</h5><ul> 413 * <li class='note'> 414 * Honored by both the next-generation engine (<c>RestClient.remote(...)</c>) and the classic engine 415 * (<c>RestClient.getRemote(...)</c>). 416 * </ul> 417 * 418 * @return The annotation value. 419 */ 420 boolean throwOnError() default false; 421}