From the user's guide, I can use annotatedWith to specify what I'd like
injected based on my own annotations. This is a great and wonderful thing.
The problem is that I still need to specify @Inject, and the question
is...why? I've already created a custom annotation, the annotation already
is bound in my module, so I know when and where it'd be used, and that
usage will always be an injection. So why the duplication?
So my proposal is to not require @Inject on custom annotations. Thoughts?
The problem is that I still need to specify @Inject, and the question
is...why?
I've already created a custom annotation, the annotation already
is bound in my module, so I know when and where it'd be used, and that
usage will always be an injection. So why the duplication?
> True, for field injection this is not the case. But field injection is
> surely the crappiest of the three so who cares? :-)
>
It's also not true for single param method injection, where most people
are likely to place the parameter on the method and not on the parameter.
> both felt that it's important to minimize the amount of naked "magic" that
> happens in a guice application. People should be able to look at their
> code
> and understand what's going to happen. Now the members of your class can
> be
> annotated with all manner of things, from @Override to @Transactional to
> @SuppressWarnings to @GuardedBy to @ReadOnly, etc. etc. If your binding
> annotation were enough to make the member be injected, how would a typical
> developer coming across your code have any idea which are the injection
> points in it?
Because in this case it's *my* annotation. It's not a random one I'm
getting from someone, it's my own, I defined it and so just as I know what
a PoopooManager does, I know what this custom annotation is. I'd say that
this is more verbose than it should be:
@Transactional
@SuppressWarnings
@Inject
@Blue
public void setWibble(...)
> I remember Bob and I discussing this and deciding it's
> cleanest to have @Inject clearly labelling every injection point.
>
> @Inject is *explicit*. That's its whole reason for existing, and in my
> own
> project, I love it.
>
This argument only works if you never want to write apps or frameworks for
other people. Using @Inject is great and perfect for 'final' code, for
anyone who writes libraries that need to be reused, using a hard
dependency on guice is not a sensible option. Nobody wants to add a hard
dependency just to support guice, but everyone wants to be able to support
it for end users who find it appealing.
Anyway, Bob assures me that all this stuff will be possible with the post
processor stuff in 1.1, so if that works as hoped then it'd take care of
this use case.
I'd say that not requiring it is a bad thing. You're right that you
don't care how something is injected, but you most certainly would be
concerned with what is being injected. You don't run into the issue
too much with constructor and setter injection, but when I look at a
class I should be able to tell the difference between methods for
injection and just plain methods.
There's also a bit of a usage contract written when you design for DI.
This obviously doesn't apply to constructor injection, but in every
other case, @Inject says that my class expects that these things are
set via whichever methods in order to be ready for use. Otherwise,
how do you tell the difference between any random property and a
dependency? Go back to the module and figure it out?
>
> On the other hand, when looking at the bootstrap code (spring xml file,
> Guice module, plan old java factory), I do care that everything happening
> should be visible to me (meaning, no invisible magic please). I love Guice
> for its static typed, simple bootstrap code, not for the @Inject spell all
> over the component classes.
>
> So what I don't get is, how is the following Guice module code confusing at
> all?
>
> //use default @Inject.
> bind(Interface1.class).to(Impl1.class);
> //use @Resource for java EE 5 entity classes that we don't want to bother
> adding @Inject to them.
> bind(Interface2.class).to(Impl2.class).withAnnotation(Resource.class);
> //use setter injection for any pojo
> bind(Interface3.class).to(Impl3.class).injectedBy(new SetterInjection());
>
> Could I please ask for a concrete use case where this "infinite" flexibility
> is used in a reasonable way but still causes confusion?
it's once you get into the whole injectedBy part. yeah, we can all
figure out setter injection, but what happens when somebody decides to
make a new form of injection named CustomInjection that applies a
regex to method names? How long am I going to spend trying to figure
out where it gets applied? How long until some stray method
accidentally matches? What about conflicts? Isn't this an open
invitation for nondeterministic modules?
>
> It's true that anything can be abused. But stopping people from doing useful
> things in fear of it might be abused with some crazy hack? I'm sure if that
> should be the rationale.
My point isn't that the world is going to come crashing down if it
gets opened up to something like this. I think that the people having
this conversation are all pretty capable of using something like this
without too many ill effects. Unfortunately, I don't think it has to
be a "crazy hack" to end up not behaving the way it was intended and I
don't see it as a solution that will work well without either serious
forethought or debugging. It's a pessimistic view, but an injection
mechanism that, by design, doesn't have expected behavior is pretty
difficult to predict.
Plus, Guice has wonderfully clear error messages that point to exactly
what the problem is most of the time. How specific can you be about
how to solve a problem when you didn't create it?
I'd say that not requiring it is a bad thing. You're right that you
don't care how something is injected, but you most certainly would be
concerned with what is being injected. You don't run into the issue
too much with constructor and setter injection, but when I look at a
class I should be able to tell the difference between methods for
injection and just plain methods.
it's once you get into the whole injectedBy part. yeah, we can all
figure out setter injection, but what happens when somebody decides to
make a new form of injection named CustomInjection that applies a
regex to method names? How long am I going to spend trying to figure
out where it gets applied? How long until some stray method
accidentally matches? What about conflicts? Isn't this an open
invitation for nondeterministic modules?
My point isn't that the world is going to come crashing down if it
gets opened up to something like this. I think that the people having
this conversation are all pretty capable of using something like this
without too many ill effects. Unfortunately, I don't think it has to
be a "crazy hack" to end up not behaving the way it was intended and I
don't see it as a solution that will work well without either serious
forethought or debugging. It's a pessimistic view, but an injection
mechanism that, by design, doesn't have expected behavior is pretty
difficult to predict.
How many times do you use an "any method" injection? To me, most of the time ctor injection is good enough.
And even if I do inject by method, the method name and javadoc usually serves better than an annotation.
init(Service serivce) clearly speaks for its purpose. I do not need an annotation to remind me what it is. We've been writing code all the time without annotations, and I never feel a need for a special annotation to serve as a documentation.
Are you saying that Guice should be created to stop people from doing all kinds of stupid things?
What about Guice complain about somebody using a "xyz123" as a method name? What about forbidding a method with more than 1000 lines of code?
What about Guice checking the Provider implementation to make sure it does not use regex or base64 to obfuscate the code? Or as Provider potentially gives programmer ability to shoot themselves, we 'd better off just removing it from Guice?
What about checking the user Module so that it is not created with some fancy reflection code and class loader tricks that will be nightmare to maintenance?
Also, doesn't bind(A.class).to(AImpl.class).injectBy(new CustomInjection()) tell you where it gets applied?
And that's exactly what I want to see. A "not crazy hack" that can end up as a tragedy. As I can tell, we are most of the time use case driven. So it'd be very helpful if other than wild imagination, a real use case can be given to support the pessimisticism.
These are all your preferences, surely you dont mandate them on the rest of us at the sacrifice of type-safe, self-documenting metadata? ;)
Absolutely it should stop people from doing stupid things in its domain as far as is possible. For methods withs funky names and improper formatting there are other domain toolkits like checkstyle. If provider can be restricted in some way to prevent stupid things happening (such as returning any Object) then it should. That's why it's parameterized!
not in its domain if you decide that is necessary.
Also, doesn't bind(A.class).to(AImpl.class).injectBy(new CustomInjection()) tell you where it gets applied?
No, it doesnt tell me anything about the dependency. It only tells me about what is available in the global injection pool. I have to lookup the module everytime I want to know what a field's semantic is--how is this any different to trawling xml bean descriptors? The module's purpose is not documentation, it is type-safe dependency binding at runtime.
And that's exactly what I want to see. A "not crazy hack" that can end up as a tragedy. As I can tell, we are most of the time use case driven. So it'd be very helpful if other than wild imagination, a real use case can be given to support the pessimisticism.
Every one of the requirements Ive seen so far for these use cases are for hiding away guice under the covers. I believe a SPI would be a worthwhile solution here, where you're free to configure the internals of guice (then make it clear to your client code that you're NOT using guice as the DI provider, just as a reflectiong and wiring engine like pico).