Skip to main content

@Remote

The @Remote annotation is used on your interface class to identify it as a REST proxy interface.

Remotepath headers headerList version versionHeader

The @Remote annotation is optional but often included for code readability.

@Remote(path)​

The @Remote(path) annotation is used to define the HTTP path of the REST service.

The path can be an absolute path to your REST service.

Example
@Remote(path="http://localhost:10000/petstore")
public interface PetStore {...}
PetStore store = client.getRemote(PetStore.class);

VarResolver.DEFAULT can also be used in the path.

Example
// URL is specified via a system property.
@Remote(path="$S{PetStoreUrl}")
public interface PetStore {...}

When a relative path is specified, it's relative to the root-url defined on the RestClient used to instantiate the interface.

Example
@Remote(path="/petstore")
public interface PetStore {...}
RestClient client = RestClient
.create()
.json()
.rootUrl("http://localhost:10000")
.build();

PetStore store = client.getRemote(PetStore.class);

When no path is specified, the root-url defined on the RestClient is used.

Example
@Remote
public interface PetStore {...}
RestClient client = RestClient
.create()
.json()
.rootUrl("http://localhost:10000/petstore")
.build();

PetStore store = client.getRemote(PetStore.class);

@Remote(headers/headerList)​

The @Remote(headers) and @Remote(headerList) annotations are used to add headers on all requests.

Example
@Remote(
path="/petstore",
headers={
"Foo: bar",
"Baz: $S{bazProperty}"
},
headerList=MyHeaderList.class
)
public interface PetStore {...}
// Our dynamic supplier.
public class MyHeaderList extends HeaderList {
...
}
Engine-specific

headerList is honored only by the classic proxy engine (RestClient.getRemote(...)). Its value type is the classic Apache-HttpClient HeaderList, which is transport-specific, so the next-generation engine cannot honor it and emits a one-time build-time warning if it is set. Use headers for transport-agnostic constant headers that work on both engines.

@Remote(version/versionHeader)​

The @Remote(version) and @Remote(versionHeader) annotations are used to specify the client-side version of this interface that can be used on the server side to perform version-specific handling.

Example
@Remote(
path="/petstore",
version="1.2.3" // Adds "Client-Version: 1.2.3" header to all requests.
)
public interface PetStore {...}

This can be used in conjunction with the server-side client-versioning support.

// Call this method if Client-Version is at least 2.0.
// Note that this also matches 2.0.1.
@RestGet(clientVersion="2.0")
public Object foo() {...}

// Call this method if Client-Version is at least 1.1 but less than 2.0.
@RestGet(clientVersion="[1.1,2.0)")
public Object foo() {...}

// Call this method if Client-Version is less than 1.1.
@RestGet(clientVersion="[0,1.1)")
public Object foo() {...}

Request-policy members​

@Remote also supports a set of interface-level request-policy members. As of 10.0.0 these are honored by both the classic (RestClient.getRemote(...)) and next-generation proxy engines — previously several of them were silently ignored by the classic engine.

MemberPurpose
baseUrlA base/host override applied to every operation (in place of the client root URL). Must use the http/https scheme.
acceptDefault Accept header (and response-parser fallback) for every operation.
contentTypeDefault Content-Type header (and request-serializer selector) for every operation.
queryDataConstant "name=value" query parameters added to every request.
formDataConstant "name=value" form-data parameters added to every request.
timeoutPer-call read/socket timeout as a duration string (e.g. "30s", "500ms").
retriesMax automatic retry attempts for safe (idempotent) operations on transport failures and retryable statuses (429/5xx).
retryNonIdempotentOpt non-idempotent verbs (POST/PATCH) into automatic retries.
throwOnErrorControls error handling for >= 400 responses (see below).

Every one of these can also be set per-operation on @RemoteOp (and the @RemoteGet/@RemotePost/... variants). The method-level value overrides the interface-level value, and the constant headers/queryData/formData entries are merged (method-level entries win on a name collision).

Example
@Remote(
path="/petstore",
accept="application/json",
timeout="30s",
retries=3,
queryData="apiKey=$S{petstore.apiKey}"
)
public interface PetStore {...}

throwOnError​

By default (throwOnError=false) a proxy call lets an HTTP error response (status >= 400) flow through:

  • If the method declares a matching HTTP-response exception in its throws clause (e.g. throws NotFound for a 404), that typed exception is thrown.
  • Otherwise the error body is returned/parsed as the normal return value.

Setting throwOnError=true additionally throws a generic BasicHttpException for any unmatched >= 400 response.

note

Methods returning void (or @RemoteOp(returns=STATUS)) never throw on an error status — a void method discards the response entirely and a STATUS method reports the code as its return value.

Engine parity​

As of 10.0.0 every @Remote/@RemoteOp member is honored by both proxy engines, except for two members that are genuinely engine-specific. Rather than silently ignore them, the proxy emits a one-time build-time warning when the member is set on the engine that cannot honor it:

MemberHonored byOn the other engine
interceptorsnext-generationThe classic engine emits a build-time warning — the classic and next-generation RestCallInterceptor SPI types are nominally incompatible (a single class cannot implement both).
headerListclassicThe next-generation engine emits a build-time warning — its value type is the classic transport-specific HeaderList. Use headers for transport-agnostic constant headers.