A Couple ColdSpring AOP Gotchas

I've been playing with ColdSpring a little on one of my personal projects, and ran into a couple gotchas that I thought I'd share.

First, if you use dynamic default values on method arguments (e.g. <cfargument name="createDate" default="#now()#" />), when ColdSpring proxies that method, the default will be converted to "[runtime expression]".  This isn't ColdSpring's fault, but rather a limitation of the getMetaData() function.  The same behaviour is visible in the CFCExplorer (which is another good reason to use CFCDoc).  As such, the only solution is to actually remove the dynamic defaults, probably just to recreate them with a structKeyExists() call inside the method body to reset the value.

Second, if you have methods with package access in your CFCs, ColdSpring will proxy them and retain the access level.  However, the proxied objects are all in package coldspring.aop.framework.tmp, which means if you have any non-proxied objects invoking those methods, CF will balk as they're no longer in the right package.  I'm not sure if ColdSpring should always create proxied methods with public access (thereby removing the runtime restrictions, but still allowing your code – particularly for generating documentation from – to indicate the "correct" access).  Regardless, as things stand today, you must change the access to public if you want the proxied method to be called from non-proxied CFCs.  There is also a "weird" scenario the other way.  Since all proxied CFCs end up in the same package, all proxied CFCs can call package methods on all other proxied CFCs, regardless of the package that the original CFCs existed in.

Aside from these two issues, I've got a transaction managment aspect running flawlessly, which means no more issues with nested transactions, and no more CFTRANSACTION tags.  I've got a little more testing to do, but I'll be releasing that here in the near future.

8 responses to “A Couple ColdSpring AOP Gotchas”

  1. Steve Bryant

    Barney,

    Is your transaction management specific to one database or can it be used on any database that supports transactions?

  2. Chris Scott

    Hey Barney. The first issue with default values, yep, I have been running into the same issue with cfproperty tags for as conversion. Flaky at best. But I think I can definitely put some thought into this package issue. There's got to be something I can do to work through that one. Well there kind of is, but it could have negative repercussions… Glad to hear that you are using CS's aop with success for transaction management. That's just a great use case there and many people love using Spring's aop based transaction management in java.

  3. Sean Corfield

    One caveat for defaults with dynamic values – are you aware that the default is *always* calculated even if the argument is passed? Using structKeyExists() inside the method is better practice, IMO.

  4. Barney

    Steve,

    The aspect is basically just a CFTRANSACTION tag, so it'll work with anything you can use CFTRANSACTION with. The only caveat (at the moment) is that you can only specify a single isolation level for your entire application. I've considered addressing that via CFFUNCTION metadata, but there's no assurance that the right method's metadata will be used, as nested/reentrant transactional method invocations don't start new transactions, and therefore don't dictate the isolation level. So the isolation level is alway specified by the first transactional method encountered.

  5. Barney

    Sean,

    That's not behaviour I've witnessed, though I haven't checked in a while. What I discovered when I did test was that CFPARAM always evaluates the default attribute, but CFARGUMENT only evaluates it if it is needed. I think I actually blogged about that at some point, now that I think about it. So using a runtime default for CFARGUMENT is safe, but a runtime default for CFPARAM is not safe.

  6. Sean Corfield

    Heh, you're right… I'm wrong… I could have sworn that used to be the case… maybe back in CFMX 6.1? But you're right that it only evaluates the default now if the argument is *not* passed in.

  7. Tony Nelson

    Aside from bringing this post back from the dead, have you found a way to use dynamic default variables in ColdSpring proxied methods? I've been toying with the idea of parsing the CFC or somehow using the property's metadata to determine the literal string ("#now()#") that could then be written into the ColdSpring generated functions, but haven't had much success yet. Just curious if you explored the idea or not.