google-code-export / google-gin

Automatically exported from code.google.com/p/google-gin
Apache License 2.0
6 stars 2 forks source link

Inject order should be constructors then fields then method #183

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
According to Guice docs (see 
http://code.google.com/p/google-guice/wiki/InjectionPoints ), the order in 
which the injection should be made is:

1- constructor injection
2- field injection
3- methods injection

(the doc says "All fields are injected and then all methods").
But in practise it happens to be (and this is not correct & usefull):

1- constructor injection
2- methods injection
3- field injection

Why it's a problem:
The problem is that you can't use class injected fields in an injected method. 
For exemple, it prevents you from writing such code (where I'm trying to put 
injected fields into a map but they are all null at that time) :

public class PresenterMapper {

    @Inject
    private Provider<ContactsPresenter> contactsProvider;

    @Inject
    private Provider<EditContactPresenter> editContactProvider;

    @Inject
    private Provider<SampleHeaderPresenter> sampleHeaderProvider;

    private Map<String, Provider<? extends Presenter>> keyToPresenterProviders;

    @Inject
    public void PresenterMapperInit() {
        keyToPresenterProviders = new HashMap<String, Provider<? extends Presenter>>();
        keyToPresenterProviders.put("shared.menu.contact.list", contactsProvider);
        keyToPresenterProviders.put("shared.menu.contact.edit", editContactProvider);
        keyToPresenterProviders.put("shared.menu.presenter.header", sampleHeaderProvider);
    }

    /** @return the Presenter associated to the given key */
    public Presenter getPresenterByKey(String key) {
        Presenter presenterToReturn = null;
        Provider<? extends Presenter> provider = keyToPresenterProviders.get(key);
        if (provider != null) {
            presenterToReturn = provider.get();
        }
        return presenterToReturn;
    }
}

The above code does not work because returns always null. One alternative would 
be to write the init method as such

@Inject
public void PresenterMapperInit(Provider<ContactsPresenter> contactsProvider,
            Provider<EditContactPresenter> editContactProvider,
            Provider<SampleHeaderPresenter> sampleHeaderProvider) {
        keyToPresenterProviders = new HashMap<String, Provider<? extends Presenter>>();
        keyToPresenterProviders.put("shared.menu.contact.list", contactsProvider);
        keyToPresenterProviders.put("shared.menu.contact.edit", editContactProvider);
        keyToPresenterProviders.put("shared.menu.presenter.header", sampleHeaderProvider);
    }
but you'll agree it's not very scalable as you add more Presenter fields into 
this class.

Behaviour reproduced on Gin 1.5 and Gin 2.0.

Original issue reported on code.google.com by francois...@gmail.com on 5 Oct 2012 at 10:20

GoogleCodeExporter commented 9 years ago
I have the same problem:

I'm trying to inject a view with editors/renderers fields marked as @Inject 
@UiField(provided=true) and then, an initialize method annotated with @Inject 
should be called last to call initWidget() when all fields have been populated.

Xavier

Original comment by xavier.d...@gmail.com on 28 Mar 2013 at 1:47

GoogleCodeExporter commented 9 years ago
in com.google.gwt.inject.rebind.util.SourceWriteUtil.createMemberInjection(), I 
think the 2 following lines should be inverted:

sb.append(createMethodInjections(getMethodsToInject(type), "injectee", 
nameGenerator, methodsOutput));
sb.append(createFieldInjections(getFieldsToInject(type), "injectee", 
nameGenerator, methodsOutput));

Original comment by xavier.d...@gmail.com on 9 Apr 2013 at 2:03

GoogleCodeExporter commented 9 years ago
Thanks. Created a patch with some tests internally.
Will let you know when it is released.

Original comment by gok...@google.com on 9 Apr 2013 at 11:30

GoogleCodeExporter commented 9 years ago
This issue was closed by revision r261.

Original comment by gin.mirr...@gmail.com on 11 Apr 2013 at 2:22

GoogleCodeExporter commented 9 years ago
Does it not make more sense to have field injection to happen as the first ? 
Just like normal java objects construction normally does ?

Original comment by david.nouls on 11 Apr 2013 at 6:57

GoogleCodeExporter commented 9 years ago
@David I don't understand... how would you inject an object that has not been 
constructed yet?

Original comment by xavier.d...@gmail.com on 11 Apr 2013 at 7:27

GoogleCodeExporter commented 9 years ago
I know, although it is counter intuitive that injected members are injected 
after construction, when in normal java objects created with new the opposite 
order is executed. I wish Java would somehow allow injection frameworks to step 
in during the object initialization.

So just disregard my comment.

Original comment by david.nouls on 11 Apr 2013 at 7:35