The Redirect Evaluator

Redirection allows a configuration file to redirect coinjema to another dependency file. Coinjema will reuse the object already created for that file if it's a shared dependency. To create a redirect file, simply determine the name of the file and append ".redirect" as its file extension. Within the file, enter the name of another dependency file.

Of course, the real question is - why do we need a redirector?

The reason is that the way Coinjema allows developers to specify names in the annotations creates an illusion of high customizability and flexibility. These things do increase flexibility slightly, but it can be a dangerous flexibility, akin to putting configuration info in the source file. To rectify this, and create real flexibility, the redirect is introduced.

Let's say we have an interface called TemplateService. We have two implementations: VelocityTemplateService and GroovyTemplateService. Now, let's say we have two classes that want to receive a shared dependency of type TemplateService.

Class A depends on TemplateService.
Class B depends on TemplateService.
These dependencies could be satisfied by a config file called TemplateService.groovy. But, what would that file return? The Velocity implementation or the Groovy implementation? What if you wanted class A to use Velocity and class B to use Groovy? You could, in class A, use @CoinjemaDependency(type="velocityTemplate") on its setTemplateService(TemplateService) method. And in class B, you could use @CoinjemaDependency(type="groovyTemplate") on its setTemplateService(TemplateService) method. Hooray for flexibility!

But wait, what you've done essentially is put configuration info into your class source files. You have succeeded in your goal of giving class A and B different implementations of TemplateService, but you now cannot cleanly1 change that just through configuration.

Enter the redirect. Instead of setting the implementation specific info in your A and B class, you can write a .redirect file that can change what A and B are pointed to. You can have a "VelocityTemplate.groovy" and a "GroovyTemplate.groovy" shared dependency, and then you can have A.setTemplateService.redirect point to "VelocityTemplate.groovy" and B.setTemplateService.redirect points to "GroovyTemplate.groovy". Now you have all your flexibility and it can be changed in the configuration rather than in your java sources.

IMPORTANT! The redirection evaluator works best for non-shared dependencies. Ie, "A.setTemplateService.redirect" is a dependency specific to class "A". It is ok (and generally expected) to point to a shared dependency from the .redirect, but it is not ok for the .redirect itself to be a shared dependency.

Furthermore, the .redirect format now supports redirection to a specific other context. For instance, instead of just pointing to "TemplateService", one can now point to "contextA/contextB/TemplateService", if desired.

The end result is that renaming the names in the annotations is a tool to increase readability. It lets you simplify your filenames too. Of course, you can still use it for ad hoc flexibility in smaller projects, if you like.

One further note about redirects. A redirect will seek to preserve the original context from which it was called. For instance, let's say we have two contexts - root and context_1. In root, we have the shared dependency TemplateService.groovy. We have the same file in context_1 returning a different implementation of our templating service. Now let's say there's a .redirect file in root pointing to "templateService". What will an object created in context "context_1" get when it's .redirect dependency file is evaluated? The object is in context_1, the .redirect is in root. The answer is, the object will get the context_1 shared templateService. The upshot of all that is that usually you only need one .redirect file at the root level to redirect all shared dependencies in all contexts - you don't need to duplicate .redirect files in every context.

1 - Of course, you could change just the configuration and make velocityTemplate.groovy return a GroovyTemplateService object. That would be ugly. Also, part of the point of the .redirect is that it preserves the sharing of the shared dependencies. A.groovyService.groovy could always return a GroovyTemplateService object, but it would not be the same instance as other classes that also wished to use it. If all classes are redirected to the one groovyTemplateService.groovy config file, then they will all reuse the same object instance, which will save on memory.