Skip to main content

Class scanning

In this tutorial we will define @Provides methods in arbitrary classes that do not implement Module interface. We will then scan those classes to collect providers to the Injector.

Classes with @Provides methods#

We will define two classes that contain methods annotated with @Provides annotation. The first class StaticProviders will contain only static @Provides-methods. The other class MixedProviders contains both static and instance @Provides-methods.

public static class StaticProviders {
@Provides
static int port() {
return 1234;
}
@Provides
static String databaseName() {
return "exampleDB";
}
}

StaticProviders class provides a name of a database as well as a database port number.

public static class MixedProviders {
private final String hostname;
public MixedProviders(String hostname) {
this.hostname = hostname;
}
@Provides
InetSocketAddress address(int port) {
return new InetSocketAddress(hostname, port);
}
@Provides
static DataSource dataSource(InetSocketAddress address, String dbName) {
return new DataSource(address, dbName);
}
}

MixedProviders class provides an address to a database and a DataSource class. DataSource class requires a database name as well as an address to a database. The class looks like this:

public static final class DataSource {
private final InetSocketAddress address;
private final String dbName;
@Inject
public DataSource(InetSocketAddress address, String dbName) {
this.address = address;
this.dbName = dbName;
}
public String queryData() {
System.out.printf("Querying %s:%s for data\n", address, dbName);
return "data";
}
}

Creating Injector#

To create an Injector we need to provide some DI modules. But we only have arbitrary classes with @Provides-methods.

We can use ModuleBuilder class to create a module based on those arbitrary classes. ModuleBuilder has multiple scan() methods that can be used to scan a class or an instance and collect providers. The whole class hierarchy is scanned, so providers defined in superclasses would also be picked up by scan().

Here is how we create an Injector:

public static void main(String[] args) {
Injector injector = Injector.of(
ModuleBuilder.create()
.scan(StaticProviders.class)
.scan(new MixedProviders("example.com"))
.build()
);
DataSource dataSource = injector.getInstance(DataSource.class);
System.out.println(dataSource.queryData());
}

For StaticProviders class that contains only static providers we do not need an instance of a class. That is why we only pass a class to the scan() method. Alternatively, MixedProviders class also contains a non-static provider method so we need to pass an instance of MixedProviders to the scan() method.

All of the collected providers form a new Module that is then being passed to the Injcetor.