Giter Club home page Giter Club logo

di1's People

Contributors

aliaspooryorik avatar mattlevine avatar seancorfield avatar seancoyne avatar sneiland avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

di1's Issues

Implicit setter logic is incorrect when property explicitly has setter="false"

In lines 233-4 of ioc.cfc you detect implicit setters as follows:

if ( implicitSetters ||
  structKeyExists( property, 'setter' ) && isBoolean( property.setter ) && property.setter ) {

This means that the following situations evaluate to true:

component accessors|persistent="true" && property setter="false"

component accessors|persistent="false" (or not set at all) && property setter="true"

In neither case do ColdFusion and Railo currently create a setter, so if you have a bean with the same name as the property di/1 tries to inject it and fails. I think the current behavior in CF and Railo is to only create implicit setters|getters when accessors|persistent is set to true? If so, I think you could fix this by changing those lines to something like this:

if ( implicitSetters && 
  ( !structKeyExists( property, 'setter' ) || isBoolean( property.setter ) && property.setter ) ) {

Extend declareBean() to add overrides

In particular, if the CFC being declared depends on a bean, it would be autowired by DI/1 based on what's in the combined bean factory, and would not need to be manually created or wired in.

This would also allow a specific bean to be overridden on a per-object basis which is not possible today based on any name-based solution (configuration or otherwise), although at the expense of asking the bean factory for a bean:

bf.declareBean( "AppDatasource", "com.system.DataSource", { dbName = "app", dbUser = "user1", dbPass = "secret" } );
bf.declareBean( "AdminDatasource", "com.system.DataSource", { dbName = "admin", dbUser = "sa", dbPass = "default" } );
// now create specific data services:
bf.declareBean( "AppService", "com.main.Service", { datasource = bf.getBean( "AppDatasource" ) } );
bf.declareBean( "AdminService", "com.main.Service", { datasource = bf.getBean( "AdminDatasource" ) } );
// that rewires what the named argument datasource is bound to for just the resolution of the xxxService bean

Using ColdSpring as parent beanFactory may throw exception

I'm using FW/1 and DI/1 in a mura plugin template. As mura uses ColdSpring internally and I wan't to provide an easy way to inject the already present mura objects in my controllers and services I try to set the application.serviceFactory as parent beanFactory of DI/1.

Therefore I've added the following two lines in my plugins Application.cfc in the setupApplication method:

<cfset local.beanFactory = new libs.ioc('/#local.pluginConfig.getPackage()#/model/services',{ exclude=['parent'] }) />
<cfset local.beanFactory.setParent(application.serviceFactory) />

When I'm trying to inject for example the cached fileManager - Bean the following exception is thrown:

Bean definition for bean named: VALUE could not be found.
/requirements/coldspring/beans/DefaultXmlBeanFactory.cfc:600

The exceptions boils down to the isSingleton() method which is integrated into the DefaultXmlBeanFactory of ColdSpring. It's behaviour is slightly different to the one you have implemented in DI/1:

If DI/1 can't find the bean, it just returns "false". If ColdSpring can't find the bean, it throws an exception.
In order to prevent this unexpected behaviour in the DI/1 world I would suggest to add a try/catch in DI/1's isSingleton function when calling the parent beanFactory:

public boolean function isSingleton( string beanName ) {
    discoverBeans( variables.folders );
    if ( structKeyExists( variables.beanInfo, beanName ) ) {
        return variables.beanInfo[ beanName ].isSingleton;
    } else if ( structKeyExists( variables, 'parent' ) ) {
        try{
            return variables.parent.isSingleton( beanName );
        } catch(any){
            return false;
        }
    } else {
        return false; // we don't know the bean therefore it is not a managed singleton
    }
}

Don't inject transients

Transients should never be injected into non-transients and probably should not be injected into other transients either.

A flag during bean-loading to fail silently for syntax errors

Use-case:

Should a syntax error in a service accidentally slip into production, in a FW/1 + DI/1 app, the whole app goes down because of the error during DI/1 startup. The more graceful solution would be for just the portion of the application that needs this service to fail. In order to do so, DI/1 needs to skip objects it's loading that contain syntax errors which would otherwise cause an exception to be thrown during startup.

Obviously you want to catch these types of errors before they get into production, so you don't want this setting on in DEV + QA environments, but I think it would be beneficial to have it as an option in production.

Need BeanFactoryAware machinery

I think setBeanFactory() or the equivalent should be enough here so DI/1 needs to automatically make a bean out of itself at startup (the way constants are handled).

Singleton cache occurs at the wrong level

Currently, singleton caching is only performed in getBean() but it needs to be performed in resolveBeanCreate() in order to ensure that multiple references to singletons found during autowiring should resolve to the same instance...

0.1.6 - Implicit setters bug

I'm referencing the sample app distributed with DI/1 0.1.6. /model/services/product.cfc has implicit setters enabled, so the userService property should be autowired a reference to /services/user.cfc. The example page dumps bf.getBean('userfish').product.getUserService() as undefined.

Improve deducibility of dotted path

If "/tests/services" is valid, expandPath("/tests/services") should be valid if the suffices match I think?

In other words, if mapping is already expanded, but we can deduce a mapping that expands to it by using a matching tail, I think that will solve the CI issue as well as make deduction more powerful generally.

declareBean()

declareBean( "name", "dotted.path", [isSingleton = true] )

Need to figure out correct metadata to add in order to make this work... Would allow programmatic addition of transients and singletons.

setParent() ?

Does this make sense? Is it "obvious"? It would help with subsystems...

Add option to suppress auto-aliasing

Add a configuration option to suppress the addition of singular-folder to bean names. Throw an exception if a naming conflict is encountered.

Remote Proxy

I would love to see remote proxy ability and allow for listing the methods to be included i.e. All, or delimited list.

Circular dependency causes stackoverflow

The following example code triggers this issue in Railo 3.3.4.003 and ACF 9.0.1.

/*
    /services/a.cfc
*/
component accessors="true" {

    property b;

}

/*
    /services/b.cfc
*/
component accessors="true" {

    property a;

}

<!--- /index.cfm --->
<cfscript>

    bf = new ioc( "/services" );

    a = bf.getBean( "a" );
    b = bf.getBean( "b" );

</cfscript>

Enhance bean factory aware hook to pass original bean name?

With bean aliases, it would be useful to be able to pass the originally requested bean name into the newly created bean. A simple way to do this would be via setBeanFactory() as a second argument (which could be ignored).

This arose from #35 (without the automaton, as a compromise).

Caching of setterMeta re: performance

I've found that for transients the findSetters() function generates a significant amount of overhead relative to the rest of the process. I found by adding variables.settersInfo = { }; to the init() and the following modification to resolveBeanCreate():

if( !structKeyExists( variables.settersInfo,beanName ) ) {
variables.settersInfo[beanName] = findSetters( bean, info.metadata );
}

var setterMeta = variables.settersInfo[beanName];

... resulted in a very large performance increase (in my case ~250ms worth of getBean() calls down to ~80ms). Perhaps my thinking doesn't encompass all cases, but it seems once the setterMeta has been captured once, it should be reusable in subsequent calls.

autoExclude should reflect new naming conventions

The variables.autoExclude setting in the init function should reflect the new naming conventions of FW/1 as well as newly added aop specific components.

variables.autoExclude = [ '/WEB-INF', '/Application.cfc', 'one.cfc', 'aop.cfc', 'beanProxy.cfc', 'WireBoxAdapter.cfc','framework.cfc', 'ioc.cfc' ];

Add ability to intercept by *type* not just name

This might be complicated and go against the run order of AOP1, but it would be great to be able to intercept beans by type (or type hirearchy) so that I can have a common interceptor for a number of beans that extend a common bean.

A use case is where I want to add a security interceptor to all my controllers in fw/1 as well as a logging interceptor that would log all calls to functions.

Guard against illegal paths

See thread on FW/1 list about DI/1 exception on line 321:

    var cfcs = directoryList( folder, variables.config.recurse, 'path', '*.cfc' );
    for ( var cfcOSPath in cfcs ) {

We should try / catch here and set cfcs to be an empty array.

Issue with using Railo 4 with strict null support when a bean has an init() method that returns null

Railo with strict null support will indicate that null variables are defined, that is, they pass an isDefined( "variableName" ) check. This means that the check on line 554:

if ( isDefined( '__ioc_newBean' ) ) {

will return true even when the init method doesn't return anything. This is easy to work around by adding return this; to the init method, but it would be nice to add an isNull() check here for completeness.

ColdSpring integration for getBeanInfo()

As I'm currently using DI/1 inside of a mura Plugin together with Taffy I'm experiencing some issues using getBeanInfo() - since Taffy relies on this method to discover it's beans.

After slightly modifying the getBeanInfo() function everything works just fine. I've changed the following line (:100)

return { beanInfo=variables.beanInfo, parent=variables.parent.getBeanInfo() };

To the following

if( isInstanceOf(variables.parent,'ioc') ){
    return { beanInfo=variables.beanInfo, parent=variables.parent.getBeanInfo() };

} else if( isInstanceOf(variables.parent,'coldspring.beans.AbstractBeanFactory') ){
    return { beanInfo=variables.beanInfo, parent=variables.parent.getBeanDefinitionList() };

} else {
    return { beanInfo=variables.beanInfo, parent={} };
}

Would be glad to see this change in the official release.

Constructor argument with required="false" causes DI/1 to throw an exception if not provided

I've got the following scenario:

<cffunction name="init" returntype="any" access="public" output="false">
    <cfargument name="apiKey"     required="true" />
    <cfargument name="apiSecret"  required="true" />
    <cfargument name="apiURL"     required="true" />
    <cfargument name="apiLocale"  required="false"  default="#getLocale()#" />
    <cfargument name="apiFormat"  required="false"  default="json" />
    ....
    <cfreturn this />
</cffunction>

This causes DI/1 to throw an exception, if the apiLocale and the apiFormat arguments are not provided in the constant structure on init - which I think is not the expected behaviour.

I'm using DI/1 for quite a while now and it's really fun to use. I would love to see it going stable soon, so if I could help pushing DI/1 forward, please let me know!

Wiki addition about paths

I have had a couple of junior(entry-level) colleagues not understand how to correctly setup a path outside the root. I suggest a statement like the following to go under the Acceptable Paths section. I realize this is not an issue with DI/1, but I think it would be helpful to beginners.

If you have trouble with DI/1 resolving an application mapping outside of your webroot, you may need to add a virtual directory that has the same name and location as the mapping in order to maintain the webroot tree path that DI/1 expects.

Feature request: add a method to get a struct of beans by suffix

Given that di1 registers beans with their containing folder as a suffix, such a method would make it possible to get a struct of all of the beans in a given folder. For example, one could call getBeans( 'services' ) and get a struct containing all of the beans in the model/services folder. This is possible to do now by calling getBeanInfo() and then iterating through the struct keys, and so this would just be a convenience method, but I thought it might be nice to have this method in di1 itself.

using [something]Bean.cfc to identify transients as well

Hi Sean, just wondering if there was a reason (other than choice) that di1 doesn't map cfc's explicitly named with the suffix "Bean" as transients as well, i.e. "userBean.cfc" becoming a transient? I see Beans living with their respective singletons often (for instance, Mura CMS with contentBean and its many related singletons within the same folder).

I use this pattern myself, and wonder if this could be an optional or automated pattern?

I've added this via:

|| right(beanName,4) eq lcase("bean")

in beanIsTransient(), so pretty easy to override if you hate the pattern ;)

Thanks for this, btw.

Signature analysis should default type to "any" if it is missing

FYI - In order to get the example working on ACF 9.0.1, I had to make
a small change to /model/beans/user.cfc

Original:

component {
function init( product ) {
this.product = product;
}
}

New:

component {
function init( any product ) {
this.product = product;
}
}

This traces back to line 95 of ioc.cfc where the data type of the
product argument is being ascertained. Apparently the type key
doesn't exist in the func.parameters struct unless the argument type
is explicitly defined. Would we want to default to "any" if the
argument type doesn't exist?

Coldspring isSingleton Issue: Updated Details moved from FW/1 Issues

My apologies for posting in wrong repo, I've added details to issue I am seeing and hoping perhaps you could shed some light on what I am doing wrong?

I can clearly trace DI/1 calling the parent.isSingleton method and passing "beanName's" that Coldspring is throwing exceptions on because it can't find the bean definition for the named bean.

I am setting up my parent bean in FW/1 in the Application.cfc as follows:

var defaultProperties = {   dsn = "newestatus"
                           ,ipConfigSiteID = "default"};
var constants = {configString = "custom config string goes here"};
var di = new lib.ioc("model,controllers");
var cs = createObject('component','coldspring.beans.DefaultXmlBeanFactory').init( defaultProperties = defaultProperties);
cs.loadBeans("../config/coldspring.xml" );
di.setParent(cs);
setBeanFactory(di);

I have traced the isSingleton function and watched it skip the first "if" and go into the next block because the "parent" variable exists and then the subsequent isSingleton call that Coldspring makes and then chokes on names like "Framework" or any other DI/1 managed resource in the model and controllers directory.

My suggest fix below:

// return true iff bean is known to be a singleton
public boolean function isSingleton( string beanName ) {
discoverBeans( variables.folders );
if ( structKeyExists( variables.beanInfo, beanName ) ) {
return variables.beanInfo[ beanName ].isSingleton;
} else if ( structKeyExists( variables, 'parent' ) ) {
try {
//ColdSpring method not sure if WireBox has this??
var beanNamesToSearch = structKeyArray(variables.parent.getBeanDefinitionList());

if( arrayfindnoCase(beanNamesToSearch,beanName) ){
return variables.parent.isSingleton( beanName );
} else {
return false;
}
} catch ( any e ) {
return false; // parent doesn't know the bean therefore is it not singleton
}
} else {
return false; // we don't know the bean therefore it is not a managed singleton
}
}

Can't use a mapping as a model path on CF9

I've been developing a project on my local CF10 install using DI/1 and passing a mapping as the model directory:

var beanFactory = new org.corfield.ioc("/app/common/model/", {constants=variables.beanProperties});

Where "/app" is defined via this.mappings["/app"] earlier in app CFC.

This works fine on CF10, but on CF9 there's an error that "/app/common/model" not found coming from this line in discoverBeansInFolder in ioc.cfc (~line 305):

var cfcs = directoryList( folder, variables.config.recurse, 'path', '*.cfc' );

Does CF9 just not support mappings in the directoryList function? Is this fixable in DI/1, or should I be doing something different?

Will try and reproduce with a smaller test case when I get a chance. Have just changed to use a full path for now.

AOP

While I understand this very early in the process di1 should have AOP ability.

DI/1 getBean improperly sets constructor (init) arguments

Given this bean 'user':

component accessors='true'{
property name='dsn';
property name='ID';

public any function init( dsn, ID=0 ){
    variables.dsn = arguments.dsn;
    variables.ID = arguments.ID;
}

}

and this bean factory initialization:

    var bf = new model.ioc( 
        folders=".,/cfc", 
        config={ 
            constants={ dsn='sample' }
        } 
    );
    setBeanFactory( bf );

when getting the bean with:
rc.result = variables.beanfactory.getBean('user');

produces a user object with both dsn and ID = 'sample'

component cfc.bean.user
PROPERTIES
dsn sample
ID sample
METHODS

Case sensitive webroot / filepath on IIS

While implementing basic walkthrough I got the following error upon setting up the bean factory and service (path starred out):
unable to deduce dot-relative paths outside webroot: **********/fw1test/model/services/greeting.cfc

A quick google search found this discussion in google groups (also where I got the title for this issue):
https://groups.google.com/forum/#!searchin/framework-one/unable$20to$20deduce$20dot-relative$20paths$20outside$20webroot/framework-one/9vgWR1pa0g8/qoxlRPzk_UEJ

I found if I changed the if check in line 287 to lcase(path).startsWith( lcase(webroot) ) I can get it to work.

Need aliases

In ColdSpring you can configure a bean to have a completely different name to its class and then define constructor and property names which have different values (scoped by the alias, effectively).

World Singles CoreColdSpring.xml has a number of examples of creating multiple configured versions from the same CFC.

Add an on missing transient bean behavior

Given a beans folder with the following transient beans:

genericTransient.cfc
user.cfc

I would like the following behavior. First as it functions now:

beanFactory.getBean( 'userBean' );
beanFactory.injectProperties( 'userBean', { } );

These return a new user.cfc with any dependencies injected, and the passed in properties set. However, I would like the option to do the following:

beanFactory.getBean( 'addressBean' );
beanFactory.injectProperties( 'addressBean', { } );

Instead of DI/1 throwing a missing bean error, I would like the option to have it give me the genericTransient.cfc, again with any dependencies injected, and passed in properties set. Obviously for this to work, the genericTransientBean is going to need to 'know' what kind of bean it is. It occurs to me that I could easily write a transientBeanFactory.cfc, have DI/1 inject itself into it, and then use the transientBeanFactory to handle requests for transients. It could then make use of DI/1's containsBean() method to either return the requested bean or a generic transient bean, setting some property on that bean so it knows what kind it is. It would be nice, though, to have this functionality handled by DI/1 itself, so that one didn't have to request transients from a different factory.

Possibly this could be done by specifying a 'default transient bean' with the convention that the requested bean name is passed into the constructor, or an onMissingTransientBean() method could be added. (Something like DI/1's current onLoad() method.) When DI/1 can't find a requested transient bean, it could pass the requested bean name to this handler, which could then decide if and how to handle the request (perhaps merely by requesting and returning a genericTransientBean from DI/1).

Parent-Bean-Factory with getParent()

Hello Sean

I have a problem with the beanFactory. My question is, why has DI/1 no functions like hasParent and getParent? I have follow problem with mura.

For the translations i need the rbFactory. And i need the beanFactory und the defaultBeanFactory. But i can't inject the defaultBeanFactory. Now i try to inject the beanFactory and get the defaultBeanFactory with getParent(), but this function doesn't exists.

Can you implement this functions or have you any ideas?

Thanks a lot
Thierry

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.