thiagobustamante / typescript-ioc

A Lightweight annotation-based dependency injection container for typescript.
MIT License
526 stars 64 forks source link

Recursive container instantiation of OnlyInstantiableByContainer classes fails #58

Closed sasha-borodin closed 4 years ago

sasha-borodin commented 4 years ago

Affected version: 3.0.3 Error: TypeError: Can not instantiate it. The instantiation is blocked for this class. Ask Container for it, using Container.get

Some properties are injected without any problems. But injection fails for classes that themselves have injected properties whose types are decorated with @OnlyInstantiableByContainer. Thus, it would seem that recursive container instantiation of @OnlyInstantiableByContainer classes is the issue. This issue manifests itself in InjectionHander class. I've stepped through the code, and here's the sequence of events:

  1. "problem" class instrumented constructor is called
  2. super(...args) succeeds ** other @OnlyInstantiableByContainer instantiation happens during this call
  3. then InjectorHandler.assertInstantiable() fails

Full stack trace:

Function.assertInstantiable (.../node_modules/typescript-ioc/dist/container/injection-handler.js:83:19)
    at new ioc_wrapper (.../node_modules/typescript-ioc/dist/container/injection-handler.js:15:33)
    at IoCBindConfig.callConstructor (.../node_modules/typescript-ioc/dist/container/container-binding-config.js:30:65)
    at .../node_modules/typescript-ioc/dist/container/container-binding-config.js:18:29
    at iocFactory (.../node_modules/typescript-ioc/dist/container/container-binding-config.js:37:30)
    at SingletonScope.resolve (.../node_modules/typescript-ioc/dist/scopes.js:21:24)
    at IoCBindConfig.getInstance (.../node_modules/typescript-ioc/dist/container/container-binding-config.js:71:30)
    at get (.../node_modules/typescript-ioc/dist/container/container.js:26:23)
    at Main.get [as _expressController] (.../node_modules/typescript-ioc/dist/container/injection-handler.js:59:72)
    at Main.start (.../dist/index.js:25:27

Screenshot of debugging session: image

thiagobustamante commented 4 years ago

Hi, @sasha-borodin ,

Thanks for reporting it. I could not reproduce it here. Can you please provide me the code of your classes for debug purpose ?

Thanks

thiagobustamante commented 4 years ago

@sasha-borodin ,

I added some tests, but could not reproduce. Take a look at this commit. Can you help me to create an example of the problem?

sasha-borodin commented 4 years ago

@thiagobustamante , please see below for an MRE:

import { Container, Inject, OnlyInstantiableByContainer, Singleton } from "typescript-ioc";

class Bar {
    baz() {
        console.info("Bar.baz() called");
    }
}

@Singleton
@OnlyInstantiableByContainer // ingredient 1
class Foo {
    @Inject
    private _bar: Bar;

    constructor() { // ingredient 2
        console.info("Foo constructor called");
        this._bar.baz(); // ingredient 3
    }
}

console.log("starting Foo instantiation");
const foo = Container.get(Foo);
console.log("successfully instantiated Foo");

The key ingredients are:

  1. Container instantiation of a @OnlyInstantiableByContainer class
  2. that class has a constructor() function (that gets instrumented by typescript-ioc)
  3. Container performs other "recursive" instantiation in that constructor function (in my example, by accessing a property on an @Injected class member).

If any of the the above doesn't hold true, the issue will NOT be seen.

Please let me know if there is anything else I can do to help. Thank you for the great framework, and your help on this matter.

thiagobustamante commented 4 years ago

Thanks @sasha-borodin .

thiagobustamante commented 4 years ago

Published in npm. Release 3.0.5