Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if you forget @Injectable() on a factory, debugging is a torture #5266

Closed
trinarytree opened this issue Nov 13, 2015 · 5 comments
Closed

if you forget @Injectable() on a factory, debugging is a torture #5266

trinarytree opened this issue Nov 13, 2015 · 5 comments
Labels
effort1: hours feature Issue that requests a new feature

Comments

@trinarytree
Copy link

try to bind something like this:

const Binding(Foo, toFactory: fooFactory)
// Notice how I don't have @Injectable() here, and why should I?
// It's not like the factory itself is injectable.
Foo fooFactory() => new Foo();

here's the completely unhelpful error message I get:

Uncaught Unhandled exception:
The null object does not have a method 'get'.

NoSuchMethodError: method not found: 'get'
Receiver: null
Arguments: [Type: class 'ExceptionHandler']
dart:core-patch/object_patch.dart 42                                      Object._noSuchMethod
dart:core-patch/object_patch.dart 45                                      Object.noSuchMethod
package:angular2/src/core/application_ref.dart 429:45                     ApplicationRef_.bootstrap.<fn>
...

nothing in the remaining stack trace hints at where the problem is.
to figure it out, you have to go to application_ref.dart:429, read a bunch of code to figure
out where the injector is getting set, guess that it's on line 268, set a breakpoint there,
try to run this.injector.resolveAndCreate yourself in the debugger, and extract a slightly more
meaningful stack trace - and i mean slightly. this is what i get:

 type '() => Map' is not a subtype of type 'Type' of 'type'.

type, type of type of type... what??
still no part of the stack trace tells me where the problem is, just that it involves the type Map.
<huge leap of imagination>
now i recall that i recently bound a Map, so i go there.
</huge leap of imagination>
nothing leaps out at me as being wrong.
so i search all over other people's code to see how they do it and see that
some, but not quite all, people put @Injectable() on their factories.
why are those other people who don't put @Injectable() not broken?
answer: they probably are but don't know it yet because their code isn't being exercised.

how about an error message more like this?:
"Injector could not create an instance for injector key because it could not find factory name.
Perhaps you forgot to annotate the factory with @Injectable()?"
of course, if you knew factory name, then why do i need to put an annotation on it?
obviously you found it. so maybe you can only say
"Injector could not create an instance for injector key because it could not find a corresponding factory. Perhaps you forgot to annotate the factory with @Injectable()?".
but at this point, i have to wonder how you found my binding. it has the factory inside it.
so let's suppose that you can't find my binding.
ok, then, how the heck did you find my binding just because i put @Injectable on a factory that it refers to?!

so basically, i have no idea what twisted things angular is doing here, but the error message needs improvement or better yet, get rid of the seemingly senseless requirement to add @Injectable() on every factory method. the boilerplate is bad enough due to forbidding anonymous factory methods.

@vicb
Copy link
Contributor

vicb commented Nov 13, 2015

Could you try const Binding(Foo, toFactory: fooFactory, deps: []).

@Injectable() is not required when you bind to a factory. I suspect that the real issue is that as there is no deps specified, the DI will try to get them using reflection info which are not present.

(The error message needs to be updated anyways)

@mhevery mhevery added feature Issue that requests a new feature P2: required effort1: hours labels Nov 15, 2015
@chalin
Copy link
Contributor

chalin commented May 20, 2016

FYI, I hit this issue while working on the angular.io Dart "Http Client" chapter. Specifically in main.dart:

void main() {
  bootstrap(AppComponent, const [
    // in-memory web api provider
    const Provider(BrowserClient,
        useFactory: HttpClientBackendServiceFactory, deps: const [])
  ]);
}

Adding deps as @vicb suggested seemed to be the work around to make DI happy. Without it, pub build reports no problems, but when I run in Dartium, from the console I get:

Exception: Cannot find reflection information on HttpClientBackendServiceFactory

cc @kwalrath @thso

@kwalrath
Copy link
Contributor

We should cover this somewhere in the docs (maybe a troubleshooting doc?), but it would of course be better if there were a helpful error message early in the dev process.

@pkozlowski-opensource
Copy link
Member

We've got TS errors covered now and Dart specific errors are obsolete. Closing this one.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
effort1: hours feature Issue that requests a new feature
Projects
None yet
Development

No branches or pull requests

6 participants