Skip to main content

juneau-shaded-rest-client

The juneau-shaded-rest-client artifact bundles all core Juneau modules plus REST client functionality. At 3.8 MB, it provides everything needed for building REST client applications.

What's Included​

This artifact includes:

  • All modules from juneau-shaded-core (marshalling, config)
  • juneau-rest-common - REST APIs common to client and server
  • juneau-rest-common-classic - REST APIs common to the classic (Apache HttpClient 4.5) client and server
  • juneau-rest-client - Transport-agnostic REST client (no Apache HttpClient dependency)
  • juneau-rest-client-classic - Legacy REST client built on Apache HttpClient 4.5

Use Cases​

Use juneau-shaded-rest-client when you need:

  • REST API consumption - Call external REST services
  • Type-safe clients - Use remote interfaces and proxies
  • Advanced HTTP features - Interceptors, authentication, retries
  • Serialization flexibility - Automatic content negotiation
  • Testing REST endpoints - Use the mock REST framework (add juneau-rest-mock as a test dependency — it is not bundled here)
Maven
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-shaded-rest-client</artifactId>
<version>${juneau.version}</version>
</dependency>
Bazel
# rules_jvm_external (MODULE.bazel / WORKSPACE maven.install)
maven.install(
artifacts = [
"org.apache.juneau:juneau-shaded-rest-client:10.0.0",
],
)
Jarjuneau-shaded-rest-client-10.0.0.jar
LinksMaven Central · Javadocs · Source

External Dependencies​

juneau-shaded-rest-client requires:

HTTP Transport​

  • None for the canonical client - the canonical juneau-rest-client has no Apache HttpClient dependency; it ships with a built-in JavaHttpTransport backed by the JDK's java.net.http.HttpClient and works out of the box on Java 11+.
  • Apache HttpClient 4.5.x - required only if you use the classic juneau-rest-client-classic client, which is built on Apache HttpClient 4.5.

Optional​

  • Apache HttpClient 4.5.x / Apache HttpClient 5.x / OkHttp / Jetty client - to swap the default JDK-HttpClient-based transport for a different native HTTP client, pull in one of the juneau-rest-client-apache-httpclient-45 / juneau-rest-client-apache-httpclient-50 / juneau-rest-client-okhttp / juneau-rest-client-jetty transport modules. Each registers a higher-priority HttpTransportProvider via ServiceLoader and is picked up automatically.
  • Jakarta XML Bind API 3.0+ - For XML serialization
  • Apache Jena - For RDF support
note

The code samples below target the canonical next-generation (NG) org.apache.juneau.rest.client.* client bundled in this shaded artifact — the headline module per What's Included above. The NG client is the recommended, generally available client in 10.0.0 and has a deliberately smaller surface than the classic client: no .json()/.basicAuth()/.oauth2Bearer() shortcuts, no RetryInterceptor. If you need those, use the bundled juneau-rest-client-classic (org.apache.juneau.rest.client.classic.*) instead — see REST Client Basics.

Example Usage​

Basic REST Call​

import org.apache.juneau.marshall.json.*;
import org.apache.juneau.rest.client.*;

public class RestClientExample {
public static void main(String[] args) throws Exception {
try (RestClient client = RestClient.builder()
.parser(JsonParser.DEFAULT)
.build()) {
// GET request
Person person = client.get("http://api.example.com/person/1")
.run()
.body().as(Person.class);

System.out.println(person.getName());
}
}
}

POST with JSON​

try (RestClient client = RestClient.builder()
.serializer(JsonSerializer.DEFAULT)
.parser(JsonParser.DEFAULT)
.build()) {
Person newPerson = new Person("John Smith", 42);

// POST JSON
Person created = client.post("http://api.example.com/person")
.body(newPerson)
.run()
.body().as(Person.class);

System.out.println("Created: " + created.getId());
}

Remote Proxies​

// Define interface
@Remote(path="/petstore")
public interface PetStore {
@RemoteGet("/pet/{petId}")
Pet getPet(@Path("petId") long id);

@RemotePost("/pet")
Pet createPet(@Content Pet pet);
}

// Use it
try (RestClient client = RestClient.builder()
.serializer(JsonSerializer.DEFAULT)
.parser(JsonParser.DEFAULT)
.build()) {
PetStore store = client.remote(PetStore.class);

Pet pet = store.getPet(123);
System.out.println(pet.getName());
}

Try-With-Resources Pattern​

try (RestClient client = RestClient.builder().parser(JsonParser.DEFAULT).build()) {
String response = client.get("/api/data").run().body().asString();
System.out.println(response);
} // Client (and its underlying transport) is automatically closed

Authentication​

The NG client has no built-in auth shortcuts (classic-only, per the note above); wire credentials in as plain headers:

// Basic authentication (manual, since there's no NG .basicAuth() shortcut)
String creds = Base64.getEncoder().encodeToString("user:password".getBytes(StandardCharsets.UTF_8));
RestClient client = RestClient.builder()
.header("Authorization", "Basic " + creds)
.build();

// Bearer token — a Supplier re-evaluates the header on every request (e.g. for token refresh)
RestClient client2 = RestClient.builder()
.header("Authorization", () -> "Bearer " + tokenSupplier.get())
.build();

Interceptors​

RestCallInterceptor is a lifecycle callback interface (onInit/onConnect/onClose), not a per-request lambda — and there is no built-in RetryInterceptor on either client stack:

RestClient client = RestClient.builder()
.interceptors(new RestCallInterceptor() {
@Override
public void onInit(RestRequest req) {
System.out.println("Calling: " + req.getUri());
}
@Override
public void onConnect(RestRequest req, RestResponse res) {
System.out.println("Status: " + res.getStatusCode());
}
})
.build();

Mock Testing​

The mock framework lives in juneau-rest-mock, which is not bundled in this shaded artifact. Add it as a separate test-scoped dependency to use MockRestClient:

import org.apache.juneau.rest.mock.*;

@Test
public void testRestClient() throws Exception {
MockRestClient client = MockRestClient.create(MyRestApi.class);

// Call the mocked API
String response = client.get("/test")
.run()
.body().asString();

assertEquals("expected", response);
}

Features​

Content Negotiation​

Automatic serialization/deserialization based on Accept and Content-Type headers (there is no dedicated .accept(String) shortcut on the NG client — set the header directly):

// Request JSON, get POJO
Person person = client.get("/person/1")
.header("Accept", "application/json")
.run()
.body().as(Person.class);

Error Handling​

try (RestClient client = RestClient.builder().build()) {
String response = client.get("/api/data")
.run()
.assertOk() // Throws RestCallException if status is not 2xx
.body().asString();
} catch (RestCallException e) {
System.err.println("HTTP " + e.getStatusCode());
}

Request/Response Assertions​

try (RestResponse resp = client.get("/api/data").run()) {
resp.assertThat()
.statusCode(200)
.header("Content-Type").contains("application/json")
.body().contains("expected");
}

Performance Characteristics​

  • Connection Pooling: Provided by the underlying HTTP transport (JDK HttpClient by default, or the transport module you plug in)
  • Keep-Alive: Automatic connection reuse
  • Streaming: Efficient memory usage for large responses
  • Async Support: Non-blocking operations available

Migration from Individual Modules​

Before:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-marshall</artifactId>
<version>${juneau.version}</version>
</dependency>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-client</artifactId>
<version>${juneau.version}</version>
</dependency>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-common</artifactId>
<version>${juneau.version}</version>
</dependency>

After:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-shaded-rest-client</artifactId>
<version>${juneau.version}</version>
</dependency>

Next Steps​