Wednesday, November 14, 2012

Injecting power with the CDI Instance Interface - Part 2

In my last post I described a way to programmatically inject a specific instance via the Instance interface. In this post I'll use the Instance interface again, but this time to inject many instances of an Object.

To start, I'll discuss why you might want to do this. One of the most common reasons I've found is in a modular application where you include different modules into one larger application. When you do this things like installers or the menu system needs to be set-up for each module. In this example we'll look at providing a dynamic menu system.

Menu Classes

Our menu is not going to be fully featured, it actually won't do anything but provide categories and options. We're going to create the following simple classes
MenuCategory.java
    public class MenuCategory {
        private String name;
        ... Accessors and Equals and HashCode Here... 
    }

MenuOption.java
    public class MenuOption {
        private MenuCategory category;
        private String name;
        ... Accessors and Equals and HashCode Here...
    }
We'll also create a Menu class that we can add all of our Options. Adding them to this class will push them into a map that uses the category as the key. You'll also notice the @Alternative qualifier. This is so that when we inject the Menu later the CDI container won't be confused.
Menu.java
    @Alternative
    public class Menu {
        private Map<MenuCategory, List<MenuOption>> menuOptions;
    
        public Menu(){
            menuOptions = new HashMap<MenuCategory, List>(10);
        }
    
        public void addOption(MenuOption option){
            if(!menuOptions.containsKey(option.getCategory())){
                menuOptions.put(option.getCategory(), new ArrayList());
            }
            menuOptions.get(option.getCategory()).add(option);
        }

        public Map<MenuCategory, List<MenuOption>> getMenuOptions() {
            return menuOptions;
        }
    }

Menu Option Provider and Menu Producer

Next we need a common way to provide the Menu Options, and we have an interface to the rescue.
public interface MenuOptionProvider {
    List<MenuOption> getMenuOptions();
}
And now we can start the fun with instances, first we'll start by making our class
public class MenuProducer {
    ...
}
And next we'll inject our Instance interface.
    @Inject @Any Instance optionProviders;
Now that we have our Instance, instead of limiting it with a qualifier, like we did in the last post, we're going to use all Instances it can find. So, instead of using the select and get methods, we're going to take advantage of the fact that it is Iterable.
    @Produces public Menu produceMenu(){
        Menu menu = new Menu();
        for(MenuOptionProvider provider:optionProviders){
            for(MenuOption option:provider.getMenuOptions()){
                menu.addOption(option);
            }
        }
        return menu;
    }
}
And that's it, we now have our dynamic menu, if you want to see it at work implement the MenuProvider like this:
public class FileMenu implements MenuOptionProvider {

    @Override
    public List getMenuOptions() {
        MenuCategory category = new MenuCategory();
        category.setName("File");

        List options = new ArrayList();

        String[] optionNames = {"Open", "Save", "Close"};

        for (String optionName : optionNames) {
            MenuOption option = new MenuOption();
            option.setCategory(category);
            option.setName(optionName);
            options.add(option);
        }

        return options;

    }
}
Download the source of this example here.

And that concludes our example today. I hope you've enjoyed this post and that it has helped you in some way.

Wednesday, November 7, 2012

Injecting power with the CDI Instance Interface - Part 1

The Instance interface in CDI is a powerful tool for creating flexible libraries and applications. In this post I'll examine a couple different ways to use Instance in your application and gain the power of programmatic injection. First, lets talk about Instance a bit. For detailed informaiton, see the Weld Reference. Instance allows a programmer to decide, at run-time, via code, which Object should be injected. This is very powerful and can be used in a few different ways. You can use the Instance interface to select a specific instance, or you can use it to run through all instances. We'll look at both of these cases with some simple examples. The first example will be creating a Factory object and will only use one instance at a time. The second example, where we'll run through many instances will wait until another post.

The factory example

In this example we'll dynamically inject a single instance that will construct an Object for us. Using this method we can create a factory that is so easy to extend that you don't need to modify it to add functionality. In this example we'll have a couple different Objects we want to create in our factory, and for fun, they won't be related whatsoever.
FirstObject.java

    public class FirstObject{
        public String value;
    }

SecondObject.java

    public class SecondObject{
        public Integer intVal;
    }
OK, we have two really simple objects that share no inheritance, and we'll have our factory create both of them; but our factory is actually going to ship the work off-shore, it will out source the work to specialized shops that we'll call ObjectBuilder.
public interface ObjectBuilder {
    Object build(String value);
}
We're providing it with some extra information just so that we can see it do more than just create a new instance. These builders will be simple to write and here they are:
FirstObjectBuilder.java

    public class FirstObjectBuilder implements ObjectBuilder{
        public Object build(String value) {
            FirstObject object = new FirstObject();
            object.value = value;
            return object;
        }
    }

SecondObjectBuilder.java

    public class SecondObjectBuilder implements ObjectBuilder{
        public Object build(String value) {
            SecondObject object = new SecondObject();
            object.intVal = Integer.parseInt(value);
            return object;
        }
    }
Finally, before we get to making our factory we need a Qualifier. This qualifier will allow us to inject the specific ObjectBuilder that we want.
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER})
public @interface BuilderFor {
    Class value();
}
We also need an Annotation Literal that we can manipulate during the CDI look-up.
public class BuilderForLiteral 
    extends AnnotationLiteral 
    implements BuilderFor{

    private Class clazz;

    public BuilderForLiteral(Class clazz) {
        this.clazz = clazz;
    }

    public Class value() {
        return clazz;
    }
}
The annotation literal provides a "physical" object that we can manipulate programmatically to represent what we're looking for.

Now that everything is in place, lets play with Instance and make our factory.
public class MyFactory{
    ...
}
The first thing we need in our factory is an Instance, so we'll inject that.
@Inject @Any Instance objectBuilderInstances;
Next, lets define our method for building:
public Object build(Class typeToBuild, String value){
    ...
}
Now, we're going to add a qualification to our Instance. This will limit the look-up to the specific ObjectBuilder we're looking for.
    BuilderForLiteral builderForQualifier = new BuilderForLiteral(typeToBuild);
    Instance qualifiedInstance 
        = objectBuilderInstances.select(builderForQualifier);
So, we now have a qualified Instance... great... we still don't have the object. But don't worry, that's the next step.
    ObjectBuilder builder = qualifiedInstance.get();
We've now injected our ObjectBuilder programmatically, the rest is pretty straight-forward.
    return builder.build(value);
And the Factory class altogether looks like this:
public class MyFactory {
    @Inject @Any Instance objectBuilderInstances;
    
    public Object build(Class typeToBuild, String value){
        BuilderForLiteral builderForQualifier = new BuilderForLiteral(typeToBuild);
        Instance qualifiedInstance 
                = objectBuilderInstances.select(builderForQualifier);
        ObjectBuilder builder = qualifiedInstance.get();
        return builder.build(value);
    }
}
This is a very powerful pattern that you can use throughout your applications, and this is just one example of using the Instance interface. Soon I'll post again about using the Instance interface to access multiple instances.

I once again want to say that this code is not production ready. For example, before we get the ObjectBuilder you should check to see if the Instance is unsatisfied or ambiguous and throw an Exception. You can use qualifiedInstance.isUnsatisfied() and qualifiedInstance.isAmbiguous() to do this.

I hope you've enjoyed this post and come back again later for more.