[wirebox-1.3.1] "Abstract" Parent Mapping (ie, like ColdSpring)

Not sure if this capability is already in wirebox or if it’s been discussed, I’m hoping someone may point me in the right direction… I’ve been using ColdBox for a while now, but with ColdSpring. I’m looking to use Wirebox on this new project…

Thanks,

In ColdSpring, you have a feature for creating abstract bean definitions and call on them on the actual implementation bean, for example:

So all my SecurityService and any other XXXServices that inherits from AbstractService, I don’t have to inject these three properties over and over, I just set the parent=“abstractService” attribute like so:

I’m curious if this is possible in WireBox’s Binder definition, I’m looking to see if something like this already exists:

// abstract objects
map(“abstractService”).asAbstract()
.asSingleton()
.property(name:“systemUtil”, ref:“systemUtil”)
.property(name:“errorFactory”, ref:“errorFactory”)
.property(name:“securityFacade”, ref:“securityFacade”);

So for every services mapping I simply do this:

// service definition(s)
map(“securityService”).to(“gov.nvlap.system.security.SecurityService”)
.abstractParent(“abstractService”)

.property(name:“userManager”, ref:“userManager”)
.property(name:“roleManager”, ref:“roleManager”)
.property(name:“logManager”, ref:“logManager”);

You could go even simpler than that, as it looks like you don’t pass anything into the objects you want to DI, but it looks like you have a custom directory than the standard models for your objects.

Now are these components being used in any other application or just this, if yes, look into the mapDirectory for the directory to be binded. Then just add the properties to the abstractService

But if the answer is no, I am guessing that what you are trying to do to the abstractService would be enough.

Quick Update:

As a workaround for this, I decided that for the two most common bean types I use on my project (service and beanManager) to create two methods that do the repetitive work and return to me the “this” scope just like all the other methods do in the core… here’s an example for services for example:

private any function mapService(required String alias, required String to)
{
map(arguments.alias).to(arguments.to)
.asSingleton()
.property(name:“systemUtil”, ref:“systemUtil”)
.property(name:“errorFactory”, ref:“errorFactory”)
.property(name:“securityFacade”, ref:“securityFacade”);

return this;
}

so in now all I have to do is:

mapService(alias:“securityService”, to:“path.to.my.SecurityService”)

.property(name:“userManager”, ref:“userManager”)

.property(name:“roleManager”, ref:“roleManager”)

.property(name:“logManager”, ref:“logManager”);

still not the most elegant solution but saves me from repetitive typing, I’ll see if I can expand on this idea with a more generic api, another thing I’ll be looking for, and please feel free to comment if there’s already a method for doing this, is the ability to break up the mapping definitions into their own files and have them included or loaded within the WireBox.cfc.

Hi Phill,

Any ideas on how you would see something like this streamlined. Since this is not XML, there are many alternatives and approaches. You could even do things like this:

getMappings()[“MyBean”] = duplicate( getMapping(“parent”) );

Luis F. Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com

ColdBox Platform: http://www.coldbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Blog: http://www.luismajano.com
IECFUG Manager: http://www.iecfug.com

Social: twitter.com/lmajano facebook.com/lmajano

Hi Luis,

First of all, welcome back buddy! Hope your trip was great, sounds like you had a great time! :slight_smile:

Your suggestion for using duplicate got me digging deeper into the mapping object and it sparked the following, I may be missing something still but this works so far, haven’t tried any complex mappings yet any feedback would be great.

But I hope it’s a decent start “draft” version of this, here’s the approach:

Define an abstract parent object:

map(“abstractService”).to(“path.to.AbstractService”)
.asSingleton()
.property(name:“someUtil”, ref:“someUtil”)
.property(name:“errorFactory”, ref:“errorFactory”)
.property(name:“someEnum”, ref:“someEnum”);

Map concrete child services using the following syntax to reuse parent dependencies:

map(“concreteService”).to(“path.to.ConcreteService”)
.parent(“abstractService”)
.property(name:“someBean”, ref:“someBean”)
.property(name:“someOtherBean”, ref:“someOtherBean”);

Here’s the .parent(“alias”) method, it copies all the parent’s dependencies:

public any function parent(required String alias)
{
// get parent mapping
var parentMapping = getMapping(name:arguments.alias);
// get parent mapping memento
var parentMemento = parentMapping.getMemento();
// get current mapping to copy parent dependencies
var currentMapping = getCurrentMapping();

var x = 1;
var key = “”;

// copy relevant parent memento to current mapping
for(key in parentMemento){

switch(key){

//process cache properties
case “cache”:
{
currentMapping.setCacheProperties(argumentCollection=parentMemento.cache);
break;
}

//process constructor args
case “DIConstructorArgs”:
{
for(x=1; x lte arrayLen(parentMemento.DIConstructorArgs); x++){
currentMapping.addDIConstructorArgument(argumentCollection=parentMemento.DIConstructorArgs[x]);
}
break;
}

//process properties
case “DIProperties” :
{
for(x=1; x lte arrayLen(parentMemento.DIProperties); x++){
currentMapping.addDIProperty(argumentCollection=parentMemento.DIProperties[x]);
}
break;
}

//process DISetters
case “DISetters” :
{
for(x=1; x lte arrayLen(parentMemento.DISetters); x++){
currentMapping.addDISetter(argumentCollection=parentMemento.DISetters[x]);
}
break;
}

//process DIMethodArgs
case “DIMethodArgs” :
{
for(x=1; x lte arrayLen(parentMemento.DIMethodArgs); x++){
currentMapping.addDIMethodArgument(argumentCollection=parentMemento.DIMethodArgs[x]);
}
break;
}

case “name”:
case “path”:
case “alias”:
{
// do nothing
break;
}

default:
{
currentMapping.getMemento()[key] = parentMemento[key];
break;
}

}// end switch

}

return this;
}

UPDATE:

Working with Luis, we were able to add this feature into the next update (3.5.1) of ColdBox and Wirebox (1.3.?). Here’s how it works:

Say you have a system utility component that you want all your service components to take advantage of, naturally you would create a parent component like AbstractService below and let your service implementations (in this scenario SecurityService and SalesService) extend it. Before, you would have to map the system utility property dependency (or initArg depending on your needs) to every actual implementation service component mapping definitions, depending on how many properties your base service has, this can be quite repetitive! You can now create a mapping definition for the parent abstract class and tell your services to use that definition as well using the new .parent(parentAlias) construct. See below for an actual example:

AbstractService.cfc - The Abstract Parent Class

Sorry, clicked submit too soon, the version of Wirebox that this will be implemented is 1.3.2 (next build)…