Back from vacations

… wait – we have vacations now 😉

It’s been a while since my last post. Finally I have decided to give the blog a new breath.

From now on, I will try rather not to enlighten the world with my Great Thoughts, but rather have a little developer journal (or kitchen journal, whatever am I up to 😉 ).

But let’s get to the post’s topic – Object Services

Before anything if you are not familiar with CDI please check out CDI’s reference implementation Weld.

A while ago Adam proposed a new take on dependency injection with injection that bases on the serviced objects.

While his implementation is very nice I always thought that it must be implementable in maybe an easier way. The thing I wanted to overcome the most was the need to inject a provider object. I thought – with proxies and generics it must be possible to call the service directly.

The idea

Hard to believe you’re not familiar with Adam’s blog, but let me explain what do we want to achieve 😉

We have a PaintService that we want to paint different animals with.

We can, of course, do many instanceof checks and then look for an appropriate service (using Factory for example), but with CDI we want the container to do it for us automatically.

So if we call paint(elephant, canvas) we would like to get the appropriate service that is capable of painting elephants and invoke the paint method on it.

My way of doing things

So here is my idea using the example in Adam’s blog:

Prerequisites – objects:

abstract class Animal
class Elephant extends Animal
class Ant extends Animal

Let’s start with defining our service’s interface.

@OS
public interface PaintService<T extends Animal> {

    void paint(T animal, Canvas c);
}

We have an interface PaintService, that is parametrized and provides a single method with the parameter object.

Three things are required

  1. The @OS annotation that marks the Object Service interface
  2. The interface must be parametrized – in the current implementation it has to be one and only one parameter
  3. All methods need to use the parametrized type
With the interface ready let’s create the implementations
@OSImpl
public class ElephantPaintService implements PaintService<Elephant>{
    @Override
    public void paint(Elephant animal, Canvas c) {
        // do some magic with the elephant and canvas
    }
}
@OSImpl
public class AntPaintService implements PaintService<Ant>{
    public void paint(Ant animal, Canvas c) {
        // do some magic with the ant and canvas
    }
}
Now let’s use it !

public class MyCoolBean {
    @Inject
    private PaintService paint;
    
    public void ourLogic(Animal a, Canvas c) {
        // do something and finally paint the animal
        paint.paint(a, c);
    }
}

If you ever need to inject your service directly, the @OSImpl annotation is a qualifier

@Inject @OSImpl
private ElephantPaintService elephantPaintService;

The code should also work nicely with Scopes and of course supports inheritance. In the above example we can pass BlackAnt extends And or RedAnt extends Ant, and the AntPaintService will be executed.

The pros and cons

  • Execution of the service is more elegant
  • … but the serviced object has to be included in every method

What can be done ?

  • Currently only one parametrized type can be used, but the implementation can be changed to support more then one.

Play with it yourself !

Everything is available in softwaremill-common/CDI module and also deployed into our Maven repository (starting from version 51-SNAPSHOT). Check out the softwaremill-common README on github for the repository URLs.

And kudos to Adam Warski for the idea.

A different take on Object Services

One thought on “A different take on Object Services

Leave a Reply

Your email address will not be published. Required fields are marked *