[coldbox-5.1.0]

I am working upgrading to 5.1.0 on ACF 2018 beta and getting an error when injecting the entity service like so

property name="ORMService" inject="entityservice";

I am thinking it might be an order of operations issue as “entityService” does not meet any of the cases in the buildDSLdependency switch statement. and the dslspec from the cborm does not seem to have run yet, but I am admittedly not very familiar with how module dsl works. I tried adding the provider namespace but then ran into issues calling ORMService.get() since the provider wrapper has a get function defined it was returning an instance of the service not the entity.
any help you can provide would be appreciated.

The DSL Definition {JAVACAST={java.lang.Object@65bef8d6},REF={java.lang.Object@65bef8d6},SCOPE={variables},REQUIRED={true},VALUE={java.lang.Object@65bef8d6},DSL={entityservice},TYPE={any},ARGNAME={},NAME={ORMService}} did not produce any resulting dependency

The target requesting the dependency is: ‘utility.EntityUtils’

The error occurred in G:/apps/lib/coldbox/5.1.0/system/ioc/Builder.cfc: line 466
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 883
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 645
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/scopes/NoScope.cfc: line 47
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 369
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Builder.cfc: line 583
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Builder.cfc: line 447
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 883
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 645
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/scopes/Singleton.cfc: line 78
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 369
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Builder.cfc: line 583
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Builder.cfc: line 414
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 883
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 645
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/scopes/Singleton.cfc: line 78
Called from G:/apps/lib/coldbox/5.1.0/system/ioc/Injector.cfc: line 369
Called from G:/apps/lib/coldbox/5.1.0/system/web/services/InterceptorService.cfc: line 328
Called from G:/apps/lib/coldbox/5.1.0/system/web/services/InterceptorService.cfc: line 259
Called from G:/apps/lib/coldbox/5.1.0/system/web/services/InterceptorService.cfc: line 115
Called from G:/apps/lib/coldbox/5.1.0/system/web/services/InterceptorService.cfc: line 85
Called from G:/apps/lib/coldbox/5.1.0/system/web/services/LoaderService.cfc: line 52
Called from G:/apps/lib/coldbox/5.1.0/system/Bootstrap.cfc: line 98
Called from G:/apps/lib/coldbox/5.1.0/system/Bootstrap.cfc: line 143
Called from G:/apps/lib/coldbox/5.1.0/system/Bootstrap.cfc: line 464
Called from G:/apps/lib/model/BaseColdboxApplication.cfc: line 182

464 : 			throw(
465 : 				message = "The DSL Definition #arguments.definition.toString()# did not produce any resulting dependency",
**466 : 				detail  = "The target requesting the dependency is: '#arguments.targetID#'",**
467 : 				type    = "Builder.DSLDependencyNotFoundException"
468 : 			);

I have traced it down to the contoller.cfc init function, it looks like the interceptor service is now getting run before the module service. can this simply be moved back to after the module service loads?

Interceptors are loaded before modules. This is a documented behavior of ColdBox and it isn’t as easy as just “moving back” part of the code. Doing so would just break other stuff. For instance, interceptors such as pre/postModule[un]load wouldn’t run any longer.

Anytime you need to inject a model from a module into an interceptor, just precede it with the “provider:” namespace which will defer it’s creation until the framework is up.

property name=“ORMService” inject=“provider:entityservice”;

As I mentioned, I tried the provider namespace, but since the cborm entityservice has a get method there is a conflict, and the onmissingmethod function in the provider does not get run. This is a change in coldbox’s behavior from version 5 to 5.1

`

5.0
// Setup the ColdBox Services
services.requestService = new coldbox.system.web.services.RequestService( this );
services.handlerService = new coldbox.system.web.services.HandlerService( this );
services.moduleService = new coldbox.system.web.services.ModuleService( this );
services.interceptorService = new coldbox.system.web.services.InterceptorService( this );

`

5.1 // Setup the ColdBox Services
services.requestService = new coldbox.system.web.services.RequestService( this );
services.interceptorService = new coldbox.system.web.services.InterceptorService( this );
services.handlerService = new coldbox.system.web.services.HandlerService( this );
services.routingService = new coldbox.system.web.services.RoutingService( this );
services.moduleService = new coldbox.system.web.services.ModuleService( this );

Sorry, I didn’t see your note about the provider namespace. All you need to do is this:

property name=“ORMServiceprovider” inject=“provider:entityservice”;

// At the point you need to use it…
realORMService = ORMServiceprovider.get();

realORMService.get( … );

When you use the provider namespace, you don’t get the actual thing you asked for, but a placeholder provider CFC with a special get() method that will return the actual object for you. The special provider CFC will proxy most methods through via onMissingMethod() but if you have an actual method called get() on your target CFC, then you need to call get() on the provider once to get the actual CFC reference and then you can use it as normal.

I’m not sure how the change above would affect this since that’s just the order that those services are created, not necessarily the order that actual interceptors and modules are loaded. Those happen at a later point in startup after the services have come online.

Hmm, I was hoping to avoid doing that since it defeats the purpose of the component property injection. At that point wouldn’t it be the same thing as calling var OrmService = wirebox.getInstance(‘EntityService’) everywhere I need it?

As for the root cause I think its because services is created as a linked hash map so the loop in the loaderservice thats calling onconfigure fore each item in the hashmap is preserving the order. Therefore the modules onconfigure method no longer gets a chance to register its service before the interceptor asks for it. I just dont understand why the order was changed in 5.1

`

LoaderService function loadApplication( overrideConfigFile="", overrideAppMapping="" ){
var coldBoxSettings = controller.getColdBoxSettings();
var services = controller.getServices();

// Load application configuration file
createAppLoader( arguments.overrideConfigFile ).loadConfiguration( arguments.overrideAppMapping );

// Do we need to create a controller decorator?
if( len( controller.getSetting( “ControllerDecorator” ) ) ){
createControllerDecorator();
}

// Check if application has loaded logbox settings so we can reconfigure, else using defaults.
if( NOT structIsEmpty( controller.getSetting( “LogBoxConfig” ) ) ){
// reconfigure LogBox with user configurations
controller.getLogBox().configure( controller.getLogBox().getConfig() );
// Reset the controller main logger
controller.setLog( controller.getLogBox().getLogger( controller ) );
}

// Clear the Cache Dictionaries, just to make sure, we are in reload mode.
controller.getHandlerService().clearDictionaries();
// Configure interceptors for operation from the configuration file
controller.getInterceptorService().configure();
// Create CacheBox
createCacheBox();
// Create WireBox Container
createWireBox();
// Execute onConfigurationLoad for coldbox internal services()
for( var thisService in services ){
services[ thisService ].onConfigurationLoad();
}
// Flag the initiation, Framework is ready to serve requests. Praise be to GOD.
controller.setColdboxInitiated( true );
// Activate All Modules
controller.getModuleService().activateAllModules();
// Execute afterConfigurationLoad
controller.getInterceptorService().processState( “afterConfigurationLoad” );
// Rebuild flash here just in case modules or afterConfigurationLoad changes settings.
controller.getRequestService().rebuildFlashScope();
// Execute afterAspectsLoad: Deprecate at one point, no more aspects as all are modules now.
controller.getInterceptorService().processState( “afterAspectsLoad” );
// We are now done, rock and roll!!
return this;
}

`

it defeats the purpose of the component property injection.

How so? There are several benefits of property injection, many of which I can think of are still intact.

At that point wouldn’t it be the same thing as calling var OrmService = wirebox.getInstance(‘EntityService’) everywhere I need it?

More less, but what is the issue there? Assuming the service is a singleton, it’s not like it’s getting re-created every time. WireBox is just handing you the reference when you ask for it. There’s nothing preventing you from persisting the CFC once you get it from the provider the first time.

As for the root cause I think its because services is created as a linked hash map so the loop in the loaderservice thats calling onconfigure fore each item in the hashmap is preserving the order. Therefore the modules onconfigure method no longer gets a chance to register its service before the interceptor asks for it.

Did the same code work in ColdBox 5? Modules are registered as part of the module service’s onConfigurationLoad method, but they aren’t activated until later. Binder mappings weren’t originally processed until a module was activated, not when it was registered. If you’re saying mappings are created and processed in the configure() method for a module then that’s probably just an accidental side effect of something that was never guaranteed to work. Modules aren’t guaranteed to be loaded until after interceptors are loaded. If you want to use a CFC from a module in an interceptor, you need to use a provider.

I just don’t understand why the order was changed in 5.1

Look in the commit log to find out. I’m sure Luis was attempting to fix another similar chicken/egg problem. Luis is on vacation at the moment so he’s unlikely to chime in.

There are several benefits of property injection, many of which I can think of are still intact.

I don’t mean to criticizes, perhaps I am just unaware of the other benefits, but the only advantages I can think of for property injection over getting the instance from wirebox is that its gotten once when the class is created, its accessible throughout the whole component and lives the life of the class. If I have to pre-get it before each subsequent use to ensure its available, I might as well just use get instance no? What other benefits am I missing?

More less, but what is the issue there? Assuming the service is a singleton, it’s not like it’s getting re-created every time. WireBox is just handing you the reference when you ask for it. There’s nothing preventing you from persisting the CFC once you get it from the provider the first time.

No issue really just that the provider namespace becomes useless if the injected class relies on a get method or onmissingmethod. without writing additional code to pre-get it each time to ensure its the actual class and not the provider. Again not complaining just observing and learning.

Did the same code work in ColdBox 5? Modules are registered as part of the module service’s onConfigurationLoad method, but they aren’t activated until later. Binder mappings weren’t originally processed until a module was activated, not when it was registered. If you’re saying mappings are created and processed in the configure() method for a module then that’s probably just an accidental side effect of something that was never guaranteed to work. Modules aren’t guaranteed to be loaded until after interceptors are loaded. If you want to use a CFC from a module in an interceptor, you need to use a provider.

Yes it worked from ~CB3.x through 5.0 rc1. CBORM registers the dsl in the on configure method, but the configure method for modules is no longer called before the interceptors are registered which causes the issue. I suppose I need to get started converting all the references over to support the service order change, I was just hoping the reordering was an unintentional oversight.

`

  • Configure Module
    */
    function configure(){
    var dslPath = “#moduleMapping#.dsl.ORMDSL”;
    // ColdBox 5
    if( variables.keyExists( “coldboxVersion” ) ){
    dslPath &= “5”;
    }

// Register Custom DSL, don’t map it because it is too late, mapping DSLs are only good by the parent app
controller.getWireBox().registerDSL( namespace=“entityService”, path=dslPath );

// Custom Declared Points
interceptorSettings = {
customInterceptionPoints = [
// CriteriaBuilder Events
“onCriteriaBuilderAddition”, “beforeCriteriaBuilderList”, “afterCriteriaBuilderList”, “beforeCriteriaBuilderCount”,
“afterCriteriaBuilderCount”,
// ORM Bridge Events
“ORMPostNew”, “ORMPreLoad”, “ORMPostLoad”, “ORMPostDelete”, “ORMPreDelete”, “ORMPreUpdate”, “ORMPostUpdate”,
“ORMPreInsert”, “ORMPostInsert”, “ORMPreSave”, “ORMPostSave”, “ORMPostFlush”, “ORMPreFlush”
]
};

// Custom Declared Interceptors
interceptors = [
];

}

`

Look in the commit log to find out. I’m sure Luis was attempting to fix another similar chicken/egg problem. Luis is on vacation at the moment so he’s unlikely to chime in.

As I mentioned above I looked through the commits and found the one thats relevant but the reason it was reordered is not readily apparent (at least to me) COLDBOX-432 #wip · ColdBox/coldbox-platform@91fc590 · GitHub

I don’t mean to be difficult I just want to make sure I understand why the change was made so I can update the code base that relies on it in the most correct manner. Thanks for your help.

perhaps I am just unaware of the other benefits, but the only advantages I can think of for property injection

My favorite benefits of property injection is the nice documentation is provides at the top of a CFC regarding the dependencies provided by our DI container as well as the nice generated getters CFML gives you like getMyPropertyName(). Property (or mixin) injection is also superior to setter and constructor injection due to its lack of boilerplate code.

The biggest reason for that change in Coldbox 5, was that moving interceptor registration before module configuration allowed for two new module lifecycle interceptions, “preModuleRegistration” and “postModuleRegistration”, which wouldn’t have been possible without changing the order.

One benefit of using providers over using an injection of an instance is that your memory footprint for those interceptors – which live in the application scope – is reduced. As you increase the number of interceptors in your application, the usage of providers can significantly reduce the processing of the request lifecycle. If your provider is calling a singleton service, there’s almost no difference in performance. I’m increasing electing to use the provider, rather than the variables scope for dependency for performance and overhead reasons. In addition, it helps me delegate singleton safety to the provided object, rather than potentially making the mistake of injecting a transient in to a singleton.

My preference is to use the provider functions, rather than property annotations because it always returns the actual class. It saves a step of having to retrieve the instance from the provider.

private function getMyService() provider=”MyService@MyModule”{}

HTH,

Jon