Skip to main content

Class scanning

In this tutorial we will define @Provides methods in arbitrary classes that do not implement the Module interface. Then we will scan these 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";
}
}

The StaticProviders class provides the database name as well as the 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);
}
}

The MixedProviders class provides the database address and the DataSource class. The DataSource class requires a database name as well as a database address. The class looks as follows:

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 the ModuleBuilder class to create a module based on these arbitrary classes. ModuleBuilder has several scan() methods that can be used to scan a class or instance and collect providers. The entire class hierarchy is scanned, so the providers defined in the superclasses would also be collected by scan().

This 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 the StaticProviders class, which contains only static providers, we do not need an instance of the class. So we only pass the class to the scan() method. Alternatively, the MixedProviders class also contains a non-static provider method, so we need to pass an instance of MixedProviders to the scan() method.

All collected providers form a new Module which is then passed to the Injcetor.

You can find example sources on Github