Tutorial 1: Basic injection - wordandahalf/Blueprint GitHub Wiki

For this series of tutorials, we will be working with these two example classes:

package blueprintTest;

public class Foo {
    private String fooText;

    public Foo() {
        this.fooText = "Hello, foo!";
    }

    public String getFoo() { return this.fooText; }
    public void sayBar() { System.out.println("Hello, bar!"); }
}

and

package blueprintTest;

public class FooInjectior {
    public static void main(String[] args) {
        Foo myFoo = new Foo();
        System.out.println(myFoo.getFoo());
        myFoo.sayBar();
    }
}

// When executed, this code will output:
// > Hello, foo!
// > Hello, bar!

In this tutorial, you will learn the simplest of injection using Blueprint: injecting code into a method. This is as simple as a few annotations and a method call.

The Blueprint annotation and the Blueprints class

Firstly, the class containing injection code must be decorated with @Blueprint. It has one parameter, target, which should be set to the fully qualified name of the class which code should be injected into.

A few caveats: Blueprint currently does not support injecting into classes that have already been loaded, nor does it support injecting into JRE system classes.

@Blueprint indicates to the BlueprintAnnotationProcessor that this class contains injection logic. However, in order for the annotation processor to scan the class, you must add it to the queue via Blueprints#add. The add method has just one parameter, clazz, the class which contains injection logic. In this case it is FooInjector.class.

Next, to apply the loaded injection logic, you have to call Blueprints#apply. This method cycles through the loaded injectors, applying them and finally loading the modified classes.

Thus, FooInjectior now looks like this:

package blueprintTest;

@Blueprint(target = "blueprintTest.Foo")
public class FooInjectior {
    public static void main(String[] args) {
        Blueprints.add(FooInjectior.class);
        Blueprints.apply();
...

That's all the setup you need! Next, we head into the world of injection with Blueprint!

The Inject annotation

@Inject is the simplest, yet most complex of the various injection annotations. It has the parameters target and at.

  • target: The case-sensitive name of the method to inject into.
  • at: The @At which describes the location within the target method to inject into.

@At has two parameters as well:

  • location: The case-insensitive location in the method which to inject into. For this tutorial, we will be injecting at the first line of the method, which is indicated by using "HEAD" for this parameter.
  • args: Any needed arguments for the location used. The simple locations need not any arguments, so this may be omitted.

For more information on @At, please see the wiki article on it.

For this tutorial, let's inject a Sysout into the Foo#getFoo() method. To do this, we need to add a new method into the FooInjector class. Here are the rules for methods decorated with @Inject:

  1. It must be a private and void method
  2. If the target method is an instance method, then the decorated method must also be an instance method. Likewise, if the target method is static, then the decorated method must also be static.
  3. It must have the same parameters as the target method

With these rules in mind, lets add a new method into our FooInjector class:

package blueprintTest;

@Blueprint(target = "blueprintTest.Foo")
public class FooInjectior {

...

    @Inject(target = "getFoo", at = @At(location = "HEAD"))
    private void getFoo() {
        System.out.println("Hello, from injection!");
    }
}

With this method added, if you were to run this code now, you would get the following output:

> Hello, from injection!
> Hello, foo!
> Hello, bar!

Congratulations! You now can use basic injection using Blueprint! There are several other tutorials to continue with, the next of which should be Tutorial #2