situation trying to use Model Integration while keeping my model free of Coldbox dependency

Hi all.

I spent quite a while late last night trying to get something to work that I was sure should have, but I did not succeed. I’m wondering if you all would mind taking a look and tell me if what I’m doing is possible and if it is, what I am doing wrong?

Think CB model integration…

I have a security handler that will use a userService model object to perform logging in and logging out. My userService object will need to be able to create instances of a user bean at different times. So, the plan is to inject the beanfactory and the datasource into my security handler via autowiring, and let the handler pass these two items to the userService via it’s constructor when the handler creates it via a private setter. My reason for wanting to do this: keep my model segregated from ColdBox as much as possible, but still take advantage of model integration.

SO, I enable the autowire interceptor. I add my userService and my userBean to my modelmappings.cfm . In my security handler, I enable autowiring, inject the datasource and the beanfactory, then leverage the onDIComplete method to then inject the userService manually via a private setter.

It all looks to me like it should work, but an error is thrown from the userService telling me that “DSN is required”; it is behaving as if userService is being instantiated without the required arguments being passed in, but, unless Coldbox is trying to instantiate my userService outside of my private setter, I cannot see why this would be true.

Any ideas? Anybody see anything wrong with the code below, or my approach to this? I am open to suggestions! I know that I can make it work if I allow my model objects to use autowiring, but my goal is to keep the model separate if at all possible.

Thanks in advance for your valuable input! And now, the relevant code:

THE COMPONENTS

.... .....

And the userService…

select * from users where userName = and password =

<cfif qryLogin.recordcount eq 1>
<cfset retval.setUsername(qryLogin.username)/>
<cfset retval.setID(qryLogin.id)/>
<cfset retval.setPassword(qryLogin.password)/>
<cfset retval.setFirstName(qryLogin.firstname)/>
<cfset retval.setLastName(qryLogin.lastname)/>
<cfset retval.setLastLoggedIn(qryLogin.lastloggedin)/>


In UserService.cfc, add name=“UserService” to the tag.

Since UserService.cfc is registered with modelmappings, it sounds like ColdBox is trying to instantiate it with init(), and since arguments are present, it’s doing DI and failiing b/c a dsn isn’t being passed in.

I’d first try making those two arguments required=“no” and see what that does for you.

Here’s another option. While I know this goes against the convention of using init() as your constructor, for testing purporses, create a method called setup() and call that in your security hanlder and see if that works as you expect.

I know neither one of these options is the solution to your problem, I hope they are steps to help you troubleshoot it.

-Dutch

So, the plan is to inject the beanfactory and the datasource into my security handler via autowiring, and let the handler pass these two items to the userService via it’s constructor when the handler creates it via a private setter
Why would you want the handler doing the wiring and creation??

My reason for wanting to do this: keep my model segregated from ColdBox as much as possible, but still take advantage of model integration
You can keep your model segrated even with model integration. You can create constructor arguments or setter injection in your model with no ties to model integration.

It seems to me you are doing maybe more thatn you are supposed to. Also this right here: getModel(“userService”)

Will tell the factory to inspect the constructor of the user service and try to match it to dependencies. So it WILL call the init method for you.

So in my opinion, it just looks kinda messy, because you are now letting your handlers do the dependency injection. There is no reason to use getModel() as you won’t get any benefits of its dependency injection features.

If you want to inject these guys manually: bf and datasource on your model objects, do them as setter injections because the constructor is inspected by the bean factory. Since setter injection is turned off by default, you can use this to wire it yourself.

One last note. If you are using the BER or nighty build, we also have a new interception point: afterModelCreation. You can then build your own autowire interceptor that can wire up model objects as per your criteria. Just remember that whenever you see a “getModel()” call, the beanfactory is instructed to create, inspect and wire the model object.

Thanks for the input Luis. That does help and I will just embrace the model integration features in full and let them do their job as designed. :slight_smile:

But it does seem to me that when you say that I can keep my model segregated but still use constructor args or setter injection as autowire mechanisms, my model then is NOT segregated. To do either one of those, I have to add attributes to either my cfargument or cffunction tags that are specific to Coldbox and Coldbox only, right? What I was hoping for in the end was a model that was free of any Coldbox-specific vernacular (modified cfproperty tags, non-cf attributes) which has no relevance outside of Coldbox and would not make sense to anybody looking at the model who did not know Coldbox.

In any event, the discussion has cleared up at least the reason why what I was trying to do would not work. Thanks again!

Doug

Hi Doug,

I have to add attributes to either my cfargument or cffunction tags that are specific to Coldbox and Coldbox only, right?
You only have to do this if you are wiring up objects that are NOT model objects. This means using anything that requires the DSL. Example: Wiring from cache, coldbox services, plugins, custom plugins, etc. Basically, anything coldboxy. However, if you are just doing model objects, the metadata is not mandatory because the bean factory assumes you are just wiring in components.

Luis

But it does seem to me that when you say that I can keep my model

segregated but still use constructor args or setter injection as
autowire mechanisms, my model then is NOT segregated. To do either one
of those, I have to add attributes to either my cfargument or cffunction
tags that are specific to Coldbox and Coldbox only, right?

No! I inject some model things in my ColdBox apps using ColdSpring and
setter injection like <cffunction name="setSomeService"
returntype="void" access="public"> and <cffunction
name="getSomeService" returntype="any" access="public">
There is no metadata or _anything_ specific to any framework there.. I
believe this is what Luis is referring to when he says "You can create
constructor arguments or setter injection in your model with no ties to
model integration."
Using this method ColdBox should simply just be looking for a
setBeanName on your model to inject the BeanName object into just like
any IOC/DI framework would.. dunno if that helps you see the bigger
picture any... but it is fairly straight forward.

Adam

Doug Boude wrote:

Thanks Adam and Luis for further clarification. It is becoming clearer, for sure. I know precisely how to think about it all using Coldspring, so relating the two does help me bridge the gap there.

And as far as being straightforward…arriving at that state is a process of personal evolution. Still evolving over here, but it is getting more straightforward daily.

Thanks again.