Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Introduction

In this quick tutorial, we’ll briefly explain Google’s AutoService.

This is an annotation processor library that helps us with generating Java Service Provider Interface (SPI) configuration files.

2. Java SPI

Simply put, we can leverage Java SPI to develop extensible applications, as it provides fast, safe, and also dynamic customizations.

Java SPI uses configuration files to find and load concrete implementations of given service provider interfaces. Customizing an application on the fly is one of its main capabilities.

On the other hand, it is easy to misconfigure and also a bit confusing for us to add or edit the configuration files. This step is also easy to forget.

Besides, there’s always a risk of typos that we may not notice, as the configuration files are not considered by the compiler.

3. Google AutoService

Google AutoService is an open source code generator tool, developed under the Google Auto project. There are also two other tools besides AutoService: AutoValue and AutoFactory.

The purpose of this library is to save effort and time and, at the same time, to prevent misconfiguration.

3.1. Maven Setup

First, let’s add the auto-service dependency in our application. We can set the dependency as optional because we only need it at compile time:

<dependency>
    <groupId>com.google.auto.service</groupId>
    <artifactId>auto-service</artifactId>
    <version>1.0-rc5</version>
    <optional>true</optional>
</dependency>

3.2. @AutoService Example

Second, we’ll create a service provider interface.

Let’s assume that our application has a translation feature. We aim to make this feature extensible. So, we can plug in any translation service provider component easily:

public interface TranslationService {
    String translate(String message, Locale from, Locale to);
}

Our application will use this interface as an extension point. An implementation on the classpath will be injected as a component.

Next, we’ll implement this service with two different translation providers using the @AutoService annotation:

@AutoService(TranslationService.class)
public class BingTranslationServiceProvider implements TranslationService {
    @Override
    public String translate(String message, Locale from, Locale to) {
        // implementation details
        return message + " (translated by Bing)"; 
    }
}
@AutoService(TranslationService.class)
public class GoogleTranslationServiceProvider implements TranslationService {
    @Override
    public String translate(String message, Locale from, Locale to) {
        // implementation details
        return message + " (translated by Google)"; 
    }
}

At the time of compilation, AutoService will look for the annotation and generate a configuration file for each of the corresponding interfaces and implementations.

As a result, we’ll now have a configuration file named com.baeldung.autoservice.TranslationService. This file contains fully-qualified names of the two of the providers:

com.baeldung.autoservice.BingTranslationServiceProvider
com.baeldung.autoservice.GoogleTranslationServiceProvider

3.3. @AutoService in Action

Now, everything is ready. Let’s load the providers through ServiceLoader:

ServiceLoader<TranslationService> loader = ServiceLoader.load(TranslationService.class);

The ServiceLoader will load every provider defined in the configuration file.

Let’s check the loaded providers count:

long count = StreamSupport.stream(loader.spliterator(), false).count();
assertEquals(2, count);

In other words, the ServiceLoader has loaded all of the provider instances. Therefore, it’s our job to select one of them.

So now, let’s pick one of the providers and then call the service method to see whether the loader works as expected:

TranslationService googleService = StreamSupport.stream(loader.spliterator(), false)
  .filter(p -> p.getClass().getSimpleName().equals("GoogleTranslationServiceProvider"))
  .findFirst()
  .get();

String message = "message";

assertEquals(message + " (translated by Google)", googleService.translate(message, null, null));

4. Conclusion

In this article, we explained the Google AutoService library and also practiced with a simple example.

Google AutoService is a useful but straightforward source code generator library. It saves us from creating and editing the service provider configuration files. It also guarantees that there won’t be any miswritten or mislocated files.

The source code of this tutorial is available on the GitHub project as usual.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of