Dependency Injection with the BeanRepository
Tags: showdev, java, coding
Published: 2018-08-23 20:23:38

---
title: Dependency Injection with the BeanRepository
published: true
description: Aaaaand another dependency injection framework.
tags: showdev, java, coding
---

Oh no, it happend again! There is it, another dependency injection framework...


# Why?

In the past I want to start a project which should be runnable in the java sandbox, and I want to use dependency injection. First I thought I can use just the dependency mechanism of Spring (`spring-context`), but that was not the case: Spring widely uses reflection, which is not allowed in the sandbox.

Nearly the same result for my next try: Guice. Now, when I tried this for my needs, there was an error with some system properties, which are not allowed to read from within the sandbox. Today I'm not able to remember which property and error exactly.

At this point, I don't want to try other frameworks, but I know there are a lot of them. For sure there are frameworks without using reflection. I thought it could be pretty cool, to create an own DI framework, and see what problems I have to solve, to match my expectations. And an other point: _coding is fun_.


# Original expectations

* some kind of dependency injection
* singleton and protoype beans
* no reflections and annotations
* configuration in java code

These expectations expands after a while. As well as I finished the project for which the `BeanRepository` was initiated.


# What happend?

However, the first result was a Service Locator. A bean has to ask activly for an other beans. Over the time the API evolved and now, I think I can say it is a mix of a Service Locator and Dependency Injection framework. It depends what you want to do, and how you do it. In [this link](https://martinfowler.com/articles/injection.html) Martin Fowler describes his idea about both approaches.


# Can I see some code?

This is a very simple example with three classes. The usecase of this program is just to print out the command line parameter.

This is our usecase, just a service:

```java
public class ArgumentPrinter {

    private final ArgsProvider argsProvider;

    /**
     * The ArgsProvider is responsible for getting the command line arguments,
     *  so we need it as a dependency. The ArgsProvider bean is provided by
     *  the BeanRepository.
     */
    public ArgumentPrinter(final ArgsProvider argsProvider) {
        this.argsProvider = argsProvider;
    }

    public void printCommandLineArgs() {

        // Isn't it a nice use case? :-)
        System.out.println("Commandline args[]:");

        for (String arg : argsProvider.get()) {
            System.out.println(" * '" + arg + "'");
        }
    }
}
```

The `BeanRepository` is kind of a container, so we need an entry point to execute our own code:

```java
/**
 * Every bean, that implements ApplicationStartedListener, will be triggered
 *  right after the BeanRepository is built. This should be used to execute code
 *  on startup.
 */
public class StartupListener extends ApplicationStartedListener {

    private final ArgumentPrinter argumentPrinter;

    public StartupListener(final ArgumentPrinter argumentPrinter) {
        this.argumentPrinter = argumentPrinter;
    }

    @Override
    public void onEvent(final ApplicationStartedEvent event) {

        // the entry point

        System.out.println("Application started");

        argumentPrinter.printCommandLineArgs();
    }
}
```

At this point we miss just a starter class, and the configuration of the `BeanRepository`.

```java
public class SimpleExampleApp implements BeanRepositoryConfigurator {

    public static void main(String[] args) {

        // Set args manually without configuring IDE run configs
        // -> not needed for real applications
        args = new String[] {"argument 1", "argument 2", "value"};

        // Start the application with dependency injection support
        //  1.: parameter: commandline args[]
        //  2.: parameter: Some class that implements BeanRepositoryConfigurator
        BeanRepositoryApplication.run(args, new SimpleExampleApp());
    }

    @Override
    public void configure(final BeanRepository.BeanRepositoryBuilder builder) {

        // This method is used to configure the available beans an how
        //  they depends on each other.
        // The scheme of the singleton method is:
        //  1.: type of the bean
        //  2.: reference to the constructor of the bean
        //  3., 4., 5., 6., 7.: the types of the needed beans

        builder
                           // type of the bean    // constructor ref    // type of reference
                .singleton(StartupListener.class, StartupListener::new, ArgumentPrinter.class)
                           // type of the bean    // constructor ref    // type of reference
                .singleton(ArgumentPrinter.class, ArgumentPrinter::new, ArgsProvider.class);
                // the ArgsProvider is a bean which is provided by the BeanRepository, to get
                //  the command line args
    }
}

```

There is a limitation of beans that can be referenced. Currently a bean can have only 5 or less dependencies. Because no reflection is used, stuff is implemented by manually coding. In this case: create interfaces with one method with different amount of parameters. For my cases it was enough.

An other point is, that cyclic references are not supported directly. It is possible, but with some extra coding. See [this example](https://github.com/tinosteinort/beanrepository/tree/master/src/test/java/com/github/tinosteinort/beanrepository/example/_03_cyclicreferenceexample).


# Other stuff

There are other functionalities, which are not listed in this post.
* other scopes
* providers
* factories
* aliases
* ...


# Where can I get it?

Try it out:

```xml
<dependency>
  <groupId>com.github.tinosteinort</groupId>
  <artifactId>beanrepository</artifactId>
  <version>1.7.0</version>
</dependency>
```

Get insights:
{% github tinosteinort/beanrepository %}