Dependency Injection in Java is easy - Part 1 - A Design Pattern
Tags: java, programming, tutorial, code
Published: 2020-08-08 12:05:17

---
title: Dependency Injection in Java is easy - Part 1 - A Design Pattern
published: true
description: This is a series of posts simplifying and exemplifying Dependency Injection in Java.
tags: ["java", "programming", "tutorial", "code"]
cover_image: https://source.unsplash.com/_SgRNwAVNKw
series: Dependency Injection in Java is easy
---

## Part 1 - A Design Pattern

This is part of a multiple-part tutorial. This first part will explain the concept of Dependency Injection, a design pattern used for achieving Inversion of Control by writing loosely coupled code.

You can check out the code for this tutorial part in [Github](https://github.com/TomerFi/dependency-injection-java-part1-tutorial).

### What is Inversion of Control

Let's visit the *wiki* definition, "[Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control) inverts the flow of control as compared to traditional control flow".

A traditional control flow is: :a: :arrow_right: :b: :arrow_right: :o2:

:a: is the customer invoking :b:, the provider that uses :o2:, the service for performing some kind of action.

- :b: controls :o2:
- :b: depends on :o2:
- :b: and :o2: are tightly coupled

*Inverting the flow of control* means decoupleing :b: from :o2: by giving the control of it to :a:. Changing the flow to: :a: (:o2:) :arrow_right: :b: :arrow_right: :x:

Now, :a: is the customer, describing :o2: the service and invoking :b: the provider for performing some action with the given service.

- :b: doesn't control :o2:
- :b: doesn't depend on :o2:
- :b: and :o2: are loosely coupled

This is achieved using Dependency Injection.

### What is Dependency Injection

Let's visit the *wiki* definition, "[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) is a technique in which an object receives other objects that it depends on."

So, Dependency Injection is a Design Pattern. Sounds less scary. Let's code.

### Mail Collector App

Let's build an app pulling emails from both *Gmail* and *Microsoft*.

#### Contracts

An *Enum* called `MailSource` for categorizing the email source:

```java
public enum MailSource {
  GMAIL,
  MICROSOFT;
}
```

An abstract class `Mail` for contracting mail objects.

```java
public abstract class Mail {
  public abstract String from();

  public abstract String subject();

  public abstract MailSource source();

  @Override
  public String toString() {
    return String.format("Got mail by %s, from %s, with the subject %s", source(), from(), subject());
  }
}
```

An interface for contracting services responsible for pulling Mail from suppliers, the `MailService`.

```java
public interface MailService {
  List<Mail> getMail();
}
```

And last, an interface for contracting an engine responsible for collecting Mail from multiple services, the `MailEngine`.

```java
public interface MailEngine {
  List<Mail> getAllMail();
}
```

#### Implementations

##### Mail

The concrete `Mail` implementations were designed with a *builder pattern* for convenience and immutability.</br>
The *Gmail* `Mail` implementation, `GmailImpl`:

```java
public final class GmailImpl extends Mail {
  private final String setFrom;
  private final String setSubject;

  private GmailImpl(final String from, final String subject) {
    setFrom = from;
    setSubject = subject;
  }

  @Override
  public String from() {
    return setFrom;
  }

  @Override
  public String subject() {
    return setSubject;
  }

  @Override
  public MailSource source() {
    return MailSource.GMAIL;
  }

  public static GmailImpl.Builder builder() {
    return new GmailImpl.Builder();
  }

  public static final class Builder {
    private String prepFrom;
    private String prepSubject;

    public Builder from(final String setFrom) {
      prepFrom = setFrom;
      return this;
    }

    public Builder subject(final String setSubject) {
      prepSubject = setSubject;
      return this;
    }

    public GmailImpl build() {
      requireNonNull(emptyToNull(prepFrom), "from cannot be empty or null");
      requireNonNull(emptyToNull(prepSubject), "subject cannot be empty or null");

      return new GmailImpl(prepFrom, prepSubject);
    }
  }
}
```

The *Micsorosft* `Mail` implementation, `MicrosoftImpl`:

```java
public final class MicrosoftImpl extends Mail {
  private final String setFrom;
  private final String setSubject;

  private MicrosoftImpl(final String from, final String subject) {
    setFrom = from;
    setSubject = subject;
  }

  @Override
  public String from() {
    return setFrom;
  }

  @Override
  public String subject() {
    return setSubject;
  }

  @Override
  public MailSource source() {
    return MailSource.MICROSOFT;
  }

  public static MicrosoftImpl.Builder builder() {
    return new MicrosoftImpl.Builder();
  }

  public static final class Builder {
    private String prepFrom;
    private String prepSubject;

    public Builder from(final String setFrom) {
      prepFrom = setFrom;
      return this;
    }

    public Builder subject(final String setSubject) {
      prepSubject = setSubject;
      return this;
    }

    public MicrosoftImpl build() {
      requireNonNull(emptyToNull(prepFrom), "from cannot be empty or null");
      requireNonNull(emptyToNull(prepSubject), "subject cannot be empty or null");

      return new MicrosoftImpl(prepFrom, prepSubject);
    }
  }
}
```

##### Mail Services

The *Gmail* `MailService` implementation:

```java
public final class GmailService implements MailService {
  @Override
  public List<Mail> getMail() {
    //This is where the actual Gmail API access goes.
    //We'll fake a couple of emails instead.
    var firstFakeMail =
        GmailImpl.builder()
            .from("a.cool.friend@gmail.com")
            .subject("wanna get together and write some code?")
            .build();

    var secondFakeMail =
        GmailImpl.builder()
            .from("an.annoying.salesman@some.company.com")
            .subject("wanna buy some stuff?")
            .build();

    return List.of(firstFakeMail, secondFakeMail);
  }
}
```

The *Microsoft* `MailService` implementation:

```java
public final class MicrosoftService implements MailService {
  @Override
  public List<Mail> getMail() {
    //This is where the actual Microsoft API access goes.
    //We'll fake a couple of emails instead.
    var firstFakeMail =
        MicrosoftImpl.builder()
            .from("my.boss@work.info")
            .subject("stop writing tutorials and get back to work!")
            .build();

    var secondFakeMail =
        MicrosoftImpl.builder()
            .from("next.door.neighbor@kibutz.org")
            .subject("do you have philips screwdriver?")
            .build();

    return List.of(firstFakeMail, secondFakeMail);
  }
}
```

##### Mail Engine

First, let's build the concrete `MailEngine` in a tightly coupled manner:

```java
public final class TightMailEngine implements MailEngine {
  private final MailService gmailService;
  private final MailService microsoftService;

  public TightMailEngine() {
    gmailService = new GmailService();
    microsoftService = new MicrosoftService();
  }

  @Override
  public List<Mail> getAllMail() {
    return concat(
            gmailService.getMail().stream(),
            microsoftService.getMail().stream())
        .collect(toList());
  }
}
```

Notice `TightMailEngine` tightly depends on both `GmailService` and `MicrosoftService`. We can fix two things in this code with Dependency Injection.

1. Testing this code is hard, invoking the *getAllMail* method will invoke the **real** *Gmail* and *Microsoft*'s services.

2. Adding another service will require modifications to `TightMailEngine`.

We can address testing by rewriting the engine loosely coupled as our first step into the Dependency Injection design pattern.

```java
public final class LooseMailEngine implements MailEngine {
  private final MailService gmailService;
  private final MailService microsoftService;

  public LooseMailEngine(final MailService setGmailService, final MailService setMicrosoftService) {
    gmailService = setGmailService;
    microsoftService = setMicrosoftService;
  }

  @Override
  public List<Mail> getAllMail() {
    return concat(
            gmailService.getMail().stream(),
            microsoftService.getMail().stream())
        .collect(toList());
  }
}
```

The `LooseMailEngine` doesn't know, nor does it depend on, either `GmailService` or `MicrosoftService`. Instead, it expects them to be injected as constructor arguments. This is **Inversion of control**. The engine no longer has control of `GmailService` or `MicrosoftService`.

From a testing perspective, we can now easily inject mocks for both `GmailService` and `MicrosoftService` and **prevent** invocation of the real services.

Now, that we have leveraged dependency injection, we rewrite `LooseMailEngine` again and make it more robust:

```java
public final class RobustMailEngine implements MailEngine {
  private final Set<MailService> mailServices;

  public RobustMailEngine(final Set<MailService> setMailSerices) {
    mailServices = setMailSerices;
  }

  @Override
  public List<Mail> getAllMail() {
    return mailServices.stream().map(MailService::getMail).flatMap(List::stream).collect(toList());
  }
}
```

Now, whoever invokes our engine has complete control of the service dependencies.</br>
:sunglasses:

#### The Main App

This is the app itself, the `MailCollectorApp`:

```java
public final class MailCollectorApp {
  private MailEngine engine;

  public MailCollectorApp(final MailEngine setEngine) {
    engine = setEngine;
  }

  public String getMail() {
    var ret = "No mail found.";
    if (!engine.getAllMail().isEmpty()) {
      ret = Joiner.on(System.lineSeparator()).join(engine.getAllMail());
    }
    return ret;
  }

  public static void main(final String... args) {
    var engine = new RobustMailEngine(List.of(new GmailService(), new MicrosoftService()));

    var app = new MailCollectorApp(engine);

    System.out.println(app.getMail());
  }
}
```

Executing the *main method* will print:

```text
Got mail by GMAIL, from a.cool.friend@gmail.com, with the subject wanna get together and write some code?
Got mail by GMAIL, from an.annoying.salesman@some.company.com, with the subject wanna buy some stuff?
Got mail by MICROSOFT, from my.boss@work.info, with the subject stop writing tutorials and get back to work!
Got mail by MICROSOFT, from next.door.neighbor@kibutz.org, with the subject do you have a star screwdriver?
```

Now, Let's test the code.

### Unit Tests

We should always prefer to test smaller units of our code while writing unit tests. However, for brevity, we're testing the *engine* and the *app* combined while mocking the *services*:

```java
public final class MailCollectorAppTest {
  private MailService gmailServiceMock;
  private MailService microsoftServiceMock;
  private MailService thirdServiceMock;

  private RobustMailEngine robustEngine;
  private MailCollectorApp sut;

  private Faker faker;

  @BeforeEach
  public void initialize() {
    faker = new Faker();

    gmailServiceMock = mock(MailService.class);
    microsoftServiceMock = mock(MailService.class);
    thirdServiceMock = mock(MailService.class);

    robustEngine =
        new RobustMailEngine(Set.of(gmailServiceMock, microsoftServiceMock, thirdServiceMock));
    sut = new MailCollectorApp(robustEngine);
  }

  @Test
  @DisplayName(
      "make the services mocks return no mail and validate the return string as 'No mail found'")
  public void getMail_noMailExists_returnsNoMailFound() {
    willReturn(emptyList()).given(gmailServiceMock).getMail();
    willReturn(emptyList()).given(microsoftServiceMock).getMail();
    willReturn(emptyList()).given(thirdServiceMock).getMail();

    then(sut.getMail()).isEqualTo("No mail found.");
  }

  @Test
  @DisplayName(
      "make the services return legitimate mail and validate the return string as expected")
  public void getMail_foundMail_returnsExpectedString() {
    var mail1 =
        GmailImpl.builder()
            .from(faker.internet().emailAddress())
            .subject(faker.lorem().sentence())
            .build();
    var mail2 =
        MicrosoftImpl.builder()
            .from(faker.internet().emailAddress())
            .subject(faker.lorem().sentence())
            .build();
    var mail3 =
        MicrosoftImpl.builder()
            .from(faker.internet().emailAddress())
            .subject(faker.lorem().sentence())
            .build();

    willReturn(List.of(mail1)).given(gmailServiceMock).getMail();
    willReturn(List.of(mail2, mail3)).given(microsoftServiceMock).getMail();
    willReturn(emptyList()).given(thirdServiceMock).getMail();

    then(sut.getMail().split(System.lineSeparator()))
        .containsOnly(mail1.toString(), mail2.toString(), mail3.toString());
  }
}
```

The next parts of this tutorial series are [Part 2 - Google Guice](https://dev.to/tomerfi/dependency-injection-in-java-is-easy-part-2-leveraging-with-google-guice-6i4) and [Part 3 - Spring Context](https://dev.to/tomerfi/dependency-injection-in-java-is-easy-part-3-leveraging-with-spring-context-gcc). We'll introduce Dependency Injection Frameworks to the above code.