Coldspring Automagic Lesson
Okay, I spent the greater part of today at work wrestling with a situation involving the injection of objects into other objects using Coldspring. After far too many hours of experimentation, furrowed brow, taking up my teammate's time, and frustration, I came to some conclusions. I can't explain the "WHY's" of the conclusions, but i can definately validate the conclusions themselves by my results.
Here's the scenario:
I have object B which extends object A. Object A has an INIT method, object B does not. Object B is being injected into object C. In my Coldspring.xml, I define a bean for object A, B, and C. Object A has a property value ("thisURL") being set via a <property> and <value> tag; object C has object B injected via a <property> and <ref> tag. (see illustration and coldspring.xml snippet)
The Challenge (there are no problems, only challenges): When all objects are instantiated, I am calling method Y on object C. Method Y itself refers to a method X in the injected object B. Method X in injected object B refers to the property "thisURL" that was set via Coldspring within object A. WE GET AN ERROR, HOWEVER, INDICATING THAT THE VALUE IN OBJECT A WAS NEVER SET!
The Experimentation:
Hmmm, let's put a CFABORT tag in the "setThisURL" method in object A (the method needed by Coldspring in order to 'auto-inject'), with a 'ShowError' attribute. The abort is never executed, meaning that Coldspring never called the 'setThisURL' method on object A, despite the fact that we configured it to do so.
Okay, let's move everything we need into object B, remove the "Extends" attribute from the cfcomponent tag, re-do our Coldspring.XML to inject the 'thisURL' property directly into object B. Hey, it works!
Let's move it all back again, and try adding an init method to object B that performs a "Super.init()" to see if that fixes it. NOPE.
In my mind, in the mind of my peers, configuring Object A to have a property value injected should have resulted in Coldspring executing the "setThisURL" method. In fact, I NEED it to do that, because I plan on utilzing this base class (object A) by extending it with other objects as well, and the constant 'thisURL' needs to be present and the same in all cases. However, it did not behave in the expected manner.
As I stated at the beginning, I have NO idea why it did not behave as I expected. But, I thought I'd share the results of my headache in case it helps someone else avoid one later.
Conclusion:
The only way to make this work was to have Coldspring set the 'thisURL' property directly in object B if I wanted to be able to access it after having extended object A.
Illustration and Coldspring.xml snippet:
Snippet:
(back to top)
Here's the scenario:
I have object B which extends object A. Object A has an INIT method, object B does not. Object B is being injected into object C. In my Coldspring.xml, I define a bean for object A, B, and C. Object A has a property value ("thisURL") being set via a <property> and <value> tag; object C has object B injected via a <property> and <ref> tag. (see illustration and coldspring.xml snippet)
The Challenge (there are no problems, only challenges): When all objects are instantiated, I am calling method Y on object C. Method Y itself refers to a method X in the injected object B. Method X in injected object B refers to the property "thisURL" that was set via Coldspring within object A. WE GET AN ERROR, HOWEVER, INDICATING THAT THE VALUE IN OBJECT A WAS NEVER SET!
The Experimentation:
Hmmm, let's put a CFABORT tag in the "setThisURL" method in object A (the method needed by Coldspring in order to 'auto-inject'), with a 'ShowError' attribute. The abort is never executed, meaning that Coldspring never called the 'setThisURL' method on object A, despite the fact that we configured it to do so.
Okay, let's move everything we need into object B, remove the "Extends" attribute from the cfcomponent tag, re-do our Coldspring.XML to inject the 'thisURL' property directly into object B. Hey, it works!
Let's move it all back again, and try adding an init method to object B that performs a "Super.init()" to see if that fixes it. NOPE.
In my mind, in the mind of my peers, configuring Object A to have a property value injected should have resulted in Coldspring executing the "setThisURL" method. In fact, I NEED it to do that, because I plan on utilzing this base class (object A) by extending it with other objects as well, and the constant 'thisURL' needs to be present and the same in all cases. However, it did not behave in the expected manner.
As I stated at the beginning, I have NO idea why it did not behave as I expected. But, I thought I'd share the results of my headache in case it helps someone else avoid one later.
Conclusion:
The only way to make this work was to have Coldspring set the 'thisURL' property directly in object B if I wanted to be able to access it after having extended object A.
Illustration and Coldspring.xml snippet:
Snippet:
<bean id="objectA" class="model.objectA" >
<property name="thisURL">
<value>http://my.testserver.com/myWS.cfc?wsdl</value>
</property>
</bean>
<bean id="objectB" class="model.objectB" />
<bean id="objectC" class="model.objectC" >
<property name="objectB">
<ref bean="objectB" />
</property>
</bean>
<property name="thisURL">
<value>http://my.testserver.com/myWS.cfc?wsdl</value>
</property>
</bean>
<bean id="objectB" class="model.objectB" />
<bean id="objectC" class="model.objectC" >
<property name="objectB">
<ref bean="objectB" />
</property>
</bean>
(back to top)
Subscription Options
You are not logged in, so your subscription status for this entry is unknown. You can login or register here.
Re: Coldspring Automagic Lesson
I suppose the most obvious question to ask is, if you add a constructor to objectB, does it work? In my opinion, all CFCs that can be instantiated should have a constructor (init() method) and unless I'm mistaken, ColdSpring makes this assumption as well.
Posted by Brian Kotek on March 6, 2007 at 1:43 AM
Re: Coldspring Automagic Lesson
Re-read the post and noticed the line about trying to add an init method. The other reason may be because I think ColdSpring actually looks at object metadata when trying to decide what to autowire, and I'm not sure the inherited method can be found there (in the subclass's metadata).
Posted by Brian Kotek on March 6, 2007 at 1:47 AM
Re: Coldspring Automagic Lesson
Ah, so going on what you're saying, PERHAPS if I move the property tag to my object B instead of object A in the coldspring, it may very well go ahead and autowire it (assuming the 'setThisURL' method is visible to Coldspring looking at the metadata of object B...)! Of course, if that DOES work it undermines my goal here: to have one place to change that URL if I need to ever change it. Hmmm. More input welcome. :D
Posted by dougboude on March 6, 2007 at 1:53 AM
Re: Coldspring Automagic Lesson
Are you saying that you expected ColdSpring to know that B extends A, and so it should set that property in B as well?
Or, Are you thinking that by having object A and object B (object, as opposed to component), anything done to A will affect B? (Sorry, it's not quite clear what is expected in that regard)
I'm ruling out order of instantiation issues, since you mentioned you were calling a method on obj c, that should alleviate any of those fears.
My best bet is that you were expecting ColdSpring to know that B extends A, and thus perform anything on B that it would perform on A. And I'm guessing it wasn't written so that it would do that (of course, it may have value but been unanticipated as well), but I could be wrong.
Do I understand correctly?
Or, Are you thinking that by having object A and object B (object, as opposed to component), anything done to A will affect B? (Sorry, it's not quite clear what is expected in that regard)
I'm ruling out order of instantiation issues, since you mentioned you were calling a method on obj c, that should alleviate any of those fears.
My best bet is that you were expecting ColdSpring to know that B extends A, and thus perform anything on B that it would perform on A. And I'm guessing it wasn't written so that it would do that (of course, it may have value but been unanticipated as well), but I could be wrong.
Do I understand correctly?
Posted by Sammy Larbi on March 6, 2007 at 7:05 AM
Re: Coldspring Automagic Lesson
Hi Sammy.
I was thinking that by telling Coldspring that object A should have the 'thisURL' property injected into it (via the 'setThisURL' method), that Coldspring would do that for me. By my object B extending object A, in my mind then object A would inherit the previously set 'thisURL' property as well. Make sense?
I was thinking that by telling Coldspring that object A should have the 'thisURL' property injected into it (via the 'setThisURL' method), that Coldspring would do that for me. By my object B extending object A, in my mind then object A would inherit the previously set 'thisURL' property as well. Make sense?
Posted by dougboude on March 6, 2007 at 11:49 AM
Re: Coldspring Automagic Lesson
Hey Doug, it looks like you are getting a bit confused by composition vs inheritance. In your xml you have defined 3 instance of 3 beans, objectA, objectB, objectC. This snippet here:
<bean id="objectA" class="model.objectA" >
<property name="thisURL">
<value>http://my.testserver.com/myWS.cfc?wsdl</value>
</property>
</bean>
Defines that an instance of objectA, which is retrieved by the identifier 'objectA' should have it's property 'thisURL' set to the value of 'http://my.testserver.com/myWS.cfc?wsdl', before it is created.
Now, the fact that object's class definition says it extends objectA has nothing to do with instances of objectA. This new instance inherits the definition for objectA, but as you have defined it, it is created without the thisURL property being set.
If you wanted objectB to contain an instance of objectA, you would need to use composition, objectA would be a property of objectB, and internally you could call getThisURL() on that to get the value. Then you would define objectB thusly:
<bean id="objectB" class="model.objectB" >
<property name="objectA">
<ref bean="objectA">
</property>
</bean>
Make sense? BTW, this text box is too damn small!
<bean id="objectA" class="model.objectA" >
<property name="thisURL">
<value>http://my.testserver.com/myWS.cfc?wsdl</value>
</property>
</bean>
Defines that an instance of objectA, which is retrieved by the identifier 'objectA' should have it's property 'thisURL' set to the value of 'http://my.testserver.com/myWS.cfc?wsdl', before it is created.
Now, the fact that object's class definition says it extends objectA has nothing to do with instances of objectA. This new instance inherits the definition for objectA, but as you have defined it, it is created without the thisURL property being set.
If you wanted objectB to contain an instance of objectA, you would need to use composition, objectA would be a property of objectB, and internally you could call getThisURL() on that to get the value. Then you would define objectB thusly:
<bean id="objectB" class="model.objectB" >
<property name="objectA">
<ref bean="objectA">
</property>
</bean>
Make sense? BTW, this text box is too damn small!
Posted by Chris Scott on March 6, 2007 at 12:22 PM
Re: Coldspring Automagic Lesson
Hey, thanks for the input Scott, much appreciated. I understand exactly what you're saying...but I don't think the solution fits my particular need here. I have a set of methods that I want to be in my base class A. I will have multiple other classes that should all inherit base class A. One of the properties of base class A is the URL to a web service, and I want to have one place where I go to change that value in the future. It made sense to me that I should use Coldspring.xml as the one location I go to for property value maintenance, which is why I was trying to set that property value via the XML file. My thought was that, because I defined my base class A bean as having that property, that when an instance of the class B (which extends base class A) is requested, Coldspring would have already set the value of base class A's 'thisURL' property for me. When it didn't work that way, that's when my head scratching began.
I now understand that since I never explicitly asked CS for the bean known as "objectA", that CS didn't bother performing the property value injection. Since I asked for the bean known as "objectB", which extended base class A, and since my bean definition for objectB didn't specify setting a value for that property, the value never got set.
As an experiment, I have now re-defined the bean for "objectB" to set the 'thisURL' property, and even though the "setThisURL" method really exists in base class A, Coldspring was able to successfully set the value for me. Lesson learned!
I now understand that since I never explicitly asked CS for the bean known as "objectA", that CS didn't bother performing the property value injection. Since I asked for the bean known as "objectB", which extended base class A, and since my bean definition for objectB didn't specify setting a value for that property, the value never got set.
As an experiment, I have now re-defined the bean for "objectB" to set the 'thisURL' property, and even though the "setThisURL" method really exists in base class A, Coldspring was able to successfully set the value for me. Lesson learned!
Posted by dougboude on March 6, 2007 at 12:49 PM
Re: Coldspring Automagic Lesson
Another way to help the multiple places to edit your URL is to use an XML entity:
[http://my.testserver.com/myWS.cfc?wsdl">]>
Then whenever you set this as a property into Object B, or other objects needing thisURL:
&thisURL;
[http://my.testserver.com/myWS.cfc?wsdl">]>
Then whenever you set this as a property into Object B, or other objects needing thisURL:
&thisURL;
Posted by Matt Williams on March 6, 2007 at 4:20 PM
Re: Coldspring Automagic Lesson
Hmmm. My post lost its code.
Define an XML entity:
&lgt;!DOCTYPE beans SYSTEM "coldspring.dtd"
[http://my.testserver.com/myWS.cfc?wsdl">]>
Then whenever you set this as a property into Object B, or other objects needing thisURL:
&thisURL;
If this post didn't work, see this blog entry for the same idea.
http://mattw.mxdj.com/controlling_the_mach_ii_or_model_glue_xml_file_size.htm
Define an XML entity:
&lgt;!DOCTYPE beans SYSTEM "coldspring.dtd"
[http://my.testserver.com/myWS.cfc?wsdl">]>
Then whenever you set this as a property into Object B, or other objects needing thisURL:
&thisURL;
If this post didn't work, see this blog entry for the same idea.
http://mattw.mxdj.com/controlling_the_mach_ii_or_model_glue_xml_file_size.htm
Posted by Matt Williams on March 6, 2007 at 4:28 PM
Re: Coldspring Automagic Lesson
Here's a thought... Why don't you reboot your machine, it solves most computer related issues ;)
Posted by Joe on March 6, 2007 at 4:45 PM
Re: Coldspring Automagic Lesson
Not sure if you ever figured it out, but the answer here is that the setup for this is incorrect. If objectB extends objectA, and objectB gets passed into objectC as a property, then you *do not* create a bean definition for objectA. Just create one for objectB and inject "thisURL" into objectB as a property. As long as setThisURL() is public in objectA, ColdSpring will correctly find the setter in the parent and use it when you create objectB.
Posted by Brian Kotek on June 12, 2007 at 9:20 AM

