A Retrofit CallAdapter for Guava's ListenableFuture
npx @tessl/cli install tessl/maven-com-squareup-retrofit2--adapter-guava@3.0.0A Retrofit CallAdapter for Guava's ListenableFuture that enables seamless integration between Retrofit HTTP client and Guava's asynchronous programming model. This adapter automatically converts Retrofit's Call objects into ListenableFuture instances, allowing service methods to return ListenableFuture instead of Call objects.
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-guava</artifactId>
<version>3.0.0</version>
</dependency>implementation 'com.squareup.retrofit2:adapter-guava:3.0.0'import retrofit2.adapter.guava.GuavaCallAdapterFactory;
import com.google.common.util.concurrent.ListenableFuture;
import retrofit2.HttpException; // For error handlingFor deprecated HttpException (not recommended):
import retrofit2.adapter.guava.HttpException; // Deprecated - use retrofit2.HttpException insteadimport retrofit2.Retrofit;
import retrofit2.adapter.guava.GuavaCallAdapterFactory;
import com.google.common.util.concurrent.ListenableFuture;
// Add the adapter to Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addCallAdapterFactory(GuavaCallAdapterFactory.create())
.build();
// Define service interface with ListenableFuture return types
interface ApiService {
@GET("users/{id}")
ListenableFuture<User> getUser(@Path("id") String userId);
@GET("users/{id}")
ListenableFuture<Response<User>> getUserWithResponse(@Path("id") String userId);
}
// Use the service
ApiService service = retrofit.create(ApiService.class);
ListenableFuture<User> userFuture = service.getUser("123");
// Add callbacks using Guava's Futures utility
Futures.addCallback(userFuture, new FutureCallback<User>() {
@Override
public void onSuccess(User user) {
// Handle successful response
}
@Override
public void onFailure(Throwable throwable) {
// Handle error (retrofit2.HttpException for HTTP errors, IOException for network errors)
}
}, MoreExecutors.directExecutor());The adapter provides two main response handling modes:
ListenableFuture<T>): Returns the deserialized response body for successful HTTP responses (2XX), and sets exceptions for errorsListenableFuture<Response<T>>): Returns the complete Response object for all HTTP responses, allowing access to headers and status codesThe adapter automatically handles:
CallCancelListenableFutureInternal Implementation:
BodyCallAdapter for direct body responses (ListenableFuture<T>)ResponseCallAdapter for Response-wrapped responses (ListenableFuture<Response<T>>)CallCancelListenableFuture (extends Guava's AbstractFuture) to handle proper cancellation propagationFactory class for creating Guava ListenableFuture call adapters.
/**
* A call adapter factory which creates Guava futures.
* Adding this class to Retrofit allows you to return ListenableFuture from service methods.
*/
public final class GuavaCallAdapterFactory extends CallAdapter.Factory {
/**
* Creates a new instance of GuavaCallAdapterFactory
* @return GuavaCallAdapterFactory instance
*/
public static GuavaCallAdapterFactory create();
/**
* Returns a call adapter for interface methods that return ListenableFuture
* @param returnType the return type to adapt
* @param annotations annotations on the declaring method
* @param retrofit the current Retrofit instance
* @return CallAdapter for ListenableFuture types, or null if not applicable
*/
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType,
Annotation[] annotations,
Retrofit retrofit
);
}The adapter supports two configurations for ListenableFuture type parameters:
// Direct body - returns deserialized body for 2XX responses
// Sets retrofit2.HttpException for non-2XX responses, IOException for network errors
ListenableFuture<User> getUser();
// Response wrapped - returns Response object for all HTTP responses
// Sets IOException for network errors only
ListenableFuture<Response<User>> getUserWithResponse();/**
* @deprecated Use retrofit2.HttpException instead
*/
@Deprecated
public final class HttpException extends retrofit2.HttpException {
/**
* Creates HTTP exception from Retrofit Response
* @param response the HTTP response that caused the exception
*/
public HttpException(Response<?> response);
}The adapter provides comprehensive error handling:
ListenableFuture<T>), the future is set with a retrofit2.HttpException containing the response detailsIllegalStateException is thrown for:
The adapter maintains full type safety:
// Parameterized types are required
ListenableFuture<User> validReturn(); // ✓ Valid
ListenableFuture<Response<User>> validReturn(); // ✓ Valid
ListenableFuture invalidReturn(); // ✗ IllegalStateException
ListenableFuture<Response> invalidReturn(); // ✗ IllegalStateExceptionThe adapter creates ListenableFuture instances that are fully compatible with Guava's concurrency utilities:
Required dependencies:
Module Configuration:
retrofit2.adapter.guavaretrofit2 and guava