ddi
Made in the European Union

Getting Started

Add DDI to your Maven build, bootstrap the container, and write your first @Inject.

1. Add the dependency

DDI is published to Maven Central. Add the artifact to your build:

<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>ddi</artifactId>
  <version>06.01.01</version>
</dependency>

Gradle (Kotlin DSL):

implementation("com.svenruppert:ddi:06.01.01")

DDI targets JDK 21+. The 1.0.x line targets JDK 8 if you need it.

2. Bootstrap the container

DDI scans the classpath for implementations, producers and resolvers. Tell it which package(s) to scan โ€” typically your application’s root:

import com.svenruppert.ddi.DI;

public class Main {
  public static void main(String[] args) {
    DI.activatePackages("com.example");
    var app = DI.activateDI(App.class);
    app.run();
  }
}

That’s the whole bootstrap. No XML, no annotation processor, no container configuration. Repeated calls to activatePackages add more packages to the scan.

3. Inject something

Field injection uses the standard javax.inject.Inject annotation:

public class App {
  @Inject Greeter greeter;

  public void run() {
    System.out.println(greeter.greet("World"));
  }
}

public interface Greeter {
  String greet(String name);
}

public class FriendlyGreeter implements Greeter {
  public String greet(String name) { return "Hello, " + name + "!"; }
}

Because exactly one implementation of Greeter is on the classpath, DDI picks FriendlyGreeter automatically. The complete decision matrix โ€” what happens with multiple impls, producers and resolvers โ€” is documented in Resolution Rules.

4. Make it dynamic

The interesting case is when several implementations exist and you want to pick one per call. Declare a ClassResolver and DDI will consult it on every @Inject:

@ResponsibleFor(Greeter.class)
public class GreeterPolicy implements ClassResolver<Greeter> {
  @Override
  public Class<? extends Greeter> resolve(Class<Greeter> i) {
    var ctx = SecurityContext.current();
    return ctx.plan() == Plan.ENTERPRISE
        ? PremiumGreeter.class
        : FriendlyGreeter.class;
  }
}

That’s the core idea of DDI: the resolver is plain Java. It can read a feature-flag service, a tenant context, a quota counter, the time of day โ€” whatever your business needs to decide which implementation comes next.

5. Where to go next

Loading packages from a file

For larger applications you can list packages in a resource file and point DDI at it via the com.svenruppert.ddi.packagesfile system property:

# good.packages
com.example.api
com.example.impl
com.example.policy
java -Dcom.svenruppert.ddi.packagesfile=packages.txt -jar app.jar

The file is read first from the classpath, then from the filesystem.