Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Dependency Injection: clarification needed(Dependenca Injection question)
icon5.gif  Dependency Injection: clarification needed [message #544309] Fri, 02 July 2010 10:03 Go to next message
No real name is currently offline No real name
Messages: 13
Registered: June 2010
Junior Member
Hello Everyone,

I am trying to understand when I can use injection in e4 and when not.

The following works very well in e4, but I do not like the solution:


public class MyClass {
@Execute
public String method1(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
return method2(shell);
}

private String method2(Shell shell) {
return method3(shell);
}

private String method3(Shell shell) {
FileDialog dialog = new FileDialog(shell, SWT.OPEN);
return dialog.open();
}
}


The following also works, and is better (the shell is now a global variable), but I still don´t like it since it creates an unecessary(???) piece of information that is available to the whole class but that nobody needs:

public class MyClass {
private Shell myShell;

@Execute
public String method1(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
myShell = shell;
return method2();
}

private String method2() {
return method3();
}

private String method3() {
FileDialog dialog = new FileDialog(myShell, SWT.OPEN);
return dialog.open();
}
}


To get rid of the global variable, I wanted to write something like the following:

public class MyClass {
@Execute
public String method1() {
return method2();
}

private String method2() {
return method3();
}

private String method3(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
FileDialog dialog = new FileDialog(shell, SWT.OPEN);
return dialog.open();
}
}


But this obviously does not work since I try to call method3(Shell) in method2() without arguments. And if give method3 a dummy shell (I am getting desperate at this point) as in the following:

public class MyClass {
@Execute
public String method1() {
return method2();
}

private String method2() {
return method3(new Shell());
}

@Inject
private String method3(IShellProvider shellProvider) {
FileDialog dialog = new FileDialog(shellProvider.getShell(), SWT.OPEN);
return dialog.open();
}
}


then method3 is called in the very begining of the application life cycle, before MyClass can be instantieted it seems like, and I get the following error:

ERROR: Unable to create class "MyClass" from bundle '675'
org.eclipse.e4.core.di.InjectionException: java.lang.IllegalArgumentException: Argument cannot be null
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(Meth odRequestor.java:49)
at org.eclipse.e4.core.internal.di.InjectorImpl.inject(Injector Impl.java:79)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(In jectorImpl.java:242)
at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorIm pl.java:196)
at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorIm pl.java:189)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(Co ntextInjectionFactory.java:129)
at org.eclipse.e4.workbench.ui.internal.ReflectionContributionF actory.createFromBundle(ReflectionContributionFactory.java:1 83)
at org.eclipse.e4.workbench.ui.internal.ReflectionContributionF actory.create(ReflectionContributionFactory.java:159)
at org.eclipse.e4.workbench.ui.internal.E4Workbench.processHier archy(E4Workbench.java:201)
at org.eclipse.e4.workbench.ui.internal.E4Workbench.init(E4Work bench.java:108)
at org.eclipse.e4.workbench.ui.internal.E4Workbench.<init>(E4Workbench.java:67)
at org.eclipse.e4.ui.workbench.swt.internal.E4Application.creat eE4Workbench(E4Application.java:173)
at org.eclipse.e4.ui.workbench.swt.internal.E4Application.start (E4Application.java:79)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(Eclips eAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher .runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher .start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseS tarter.java:369)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseS tarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java: 619)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:574)
at org.eclipse.equinox.launcher.Main.run(Main.java:1407)
at org.eclipse.equinox.launcher.Main.main(Main.java:1383)
Caused by: java.lang.IllegalArgumentException: Argument cannot be null
at org.eclipse.swt.SWT.error(SWT.java:4064)
at org.eclipse.swt.SWT.error(SWT.java:3998)
at org.eclipse.swt.SWT.error(SWT.java:3969)
at org.eclipse.swt.widgets.Dialog.error(Dialog.java:198)
at org.eclipse.swt.widgets.Dialog.checkParent(Dialog.java:164)
at org.eclipse.swt.widgets.Dialog.<init>(Dialog.java:127)
at org.eclipse.swt.widgets.FileDialog.<init>(FileDialog.java:109)
at MyClass.method3(MyClass.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(Meth odRequestor.java:42)
... 25 more


In other words: I hope someone can explain to me when and how dependency injection can and cannot be used. Preferably by explaining what is going wrong in the last code samples.

I am using Eclipse e4 M6.

Many thanks in advance,
Karin
Re: Dependency Injection: clarification needed [message #544321 is a reply to message #544309] Fri, 02 July 2010 10:57 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5434
Registered: July 2009
Senior Member
Hi,

I'm not sure what you are doing/solve here, what you present is a
handler implementation (i take this from your stacktrace).

In handlers you are NOT useing @Inject (we don't yet really support this
there - Paul could give you the reason on why this is not yet supported)
but only @Execute and @CanExecute.

The first class you show is the perfect solution when implementing a
handler, whenever your handler is executed it gets the current active
shell. I don't understand why the 2nd code is better in any way and the
3rd one would not even compile, 4th doesn't make sense at all in a Handler.

Tom

Am 02.07.10 12:03, schrieb karins.spam@gmail.com:
> Hello Everyone,
>
> I am trying to understand when I can use injection in e4 and when not.
> The following works very well in e4, but I do not like the solution:
>
>
> public class MyClass {
> @Execute
> public String method1(@Named(IServiceConstants.ACTIVE_SHELL) Shell
> shell) {
> return method2(shell);
> }
>
> private String method2(Shell shell) {
> return method3(shell);
> }
>
> private String method3(Shell shell) {
> FileDialog dialog = new FileDialog(shell, SWT.OPEN);
> return dialog.open();
> }
> }
>
> The following also works, and is better (the shell is now a global
> variable), but I still don´t like it since it creates an unecessary(???)
> piece of information that is available to the whole class but that
> nobody needs:
>
> public class MyClass {
> private Shell myShell;
>
> @Execute
> public String method1(@Named(IServiceConstants.ACTIVE_SHELL) Shell
> shell) {
> myShell = shell;
> return method2();
> }
>
> private String method2() {
> return method3();
> }
>
> private String method3() {
> FileDialog dialog = new FileDialog(myShell, SWT.OPEN);
> return dialog.open();
> }
> }
>
> To get rid of the global variable, I wanted to write something like the
> following:
>
> public class MyClass {
> @Execute
> public String method1() {
> return method2();
> }
>
> private String method2() {
> return method3();
> }
>
> private String method3(@Named(IServiceConstants.ACTIVE_SHELL) Shell
> shell) {
> FileDialog dialog = new FileDialog(shell, SWT.OPEN);
> return dialog.open();
> }
> }
>
> But this obviously does not work since I try to call method3(Shell) in
> method2() without arguments. And if give method3 a dummy shell (I am
> getting desperate at this point) as in the following:
>
> public class MyClass {
> @Execute
> public String method1() {
> return method2();
> }
>
> private String method2() {
> return method3(new Shell());
> }
>
> @Inject
> private String method3(IShellProvider shellProvider) {
> FileDialog dialog = new FileDialog(shellProvider.getShell(),
> SWT.OPEN);
> return dialog.open();
> }
> }
>
> then method3 is called in the very begining of the application life
> cycle, before MyClass can be instantieted it seems like, and I get the
> following error:
> ERROR: Unable to create class "MyClass" from bundle '675'
> org.eclipse.e4.core.di.InjectionException:
> java.lang.IllegalArgumentException: Argument cannot be null
> at org.eclipse.e4.core.internal.di.MethodRequestor.execute(Meth
> odRequestor.java:49)
> at org.eclipse.e4.core.internal.di.InjectorImpl.inject(Injector
> Impl.java:79)
> at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(In
> jectorImpl.java:242)
> at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorIm
> pl.java:196)
> at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorIm
> pl.java:189)
> at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(Co
> ntextInjectionFactory.java:129)
> at org.eclipse.e4.workbench.ui.internal.ReflectionContributionF
> actory.createFromBundle(ReflectionContributionFactory.java:1 83)
> at org.eclipse.e4.workbench.ui.internal.ReflectionContributionF
> actory.create(ReflectionContributionFactory.java:159)
> at org.eclipse.e4.workbench.ui.internal.E4Workbench.processHier
> archy(E4Workbench.java:201)
> at org.eclipse.e4.workbench.ui.internal.E4Workbench.init(E4Work
> bench.java:108)
> at
> org.eclipse.e4.workbench.ui.internal.E4Workbench.<init>(E4Workbench.java:67)
>
> at org.eclipse.e4.ui.workbench.swt.internal.E4Application.creat
> eE4Workbench(E4Application.java:173)
> at org.eclipse.e4.ui.workbench.swt.internal.E4Application.start
> (E4Application.java:79)
> at org.eclipse.equinox.internal.app.EclipseAppHandle.run(Eclips
> eAppHandle.java:196)
> at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher
> .runApplication(EclipseAppLauncher.java:110)
> at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher
> .start(EclipseAppLauncher.java:79)
> at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseS
> tarter.java:369)
> at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseS
> tarter.java:179)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> at java.lang.reflect.Method.invoke(Unknown Source)
> at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java: 619)
> at org.eclipse.equinox.launcher.Main.basicRun(Main.java:574)
> at org.eclipse.equinox.launcher.Main.run(Main.java:1407)
> at org.eclipse.equinox.launcher.Main.main(Main.java:1383)
> Caused by: java.lang.IllegalArgumentException: Argument cannot be null
> at org.eclipse.swt.SWT.error(SWT.java:4064)
> at org.eclipse.swt.SWT.error(SWT.java:3998)
> at org.eclipse.swt.SWT.error(SWT.java:3969)
> at org.eclipse.swt.widgets.Dialog.error(Dialog.java:198)
> at org.eclipse.swt.widgets.Dialog.checkParent(Dialog.java:164)
> at org.eclipse.swt.widgets.Dialog.<init>(Dialog.java:127)
> at org.eclipse.swt.widgets.FileDialog.<init>(FileDialog.java:109)
> at MyClass.method3(MyClass.java:12)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> at java.lang.reflect.Method.invoke(Unknown Source)
> at org.eclipse.e4.core.internal.di.MethodRequestor.execute(Meth
> odRequestor.java:42)
> ... 25 more
>
> In other words: I hope someone can explain to me when and how dependency
> injection can and cannot be used. Preferably by explaining what is going
> wrong in the last code samples.
>
> I am using Eclipse e4 M6.
>
> Many thanks in advance,
> Karin
Re: Dependency Injection: clarification needed [message #544332 is a reply to message #544321] Fri, 02 July 2010 11:50 Go to previous messageGo to next message
No real name is currently offline No real name
Messages: 13
Registered: June 2010
Junior Member
Hi Tom,

and thanks for the quick response.

You are correct in that it is a Handler. I wasn´t saying that since I didn´t think it was relevant. I thought that the depency injection would work in any POJO independently of when/how it was being instantiated.

I thought the idea of di was that whenever you needed an object, in this case a shell, you could just inject the providing service, and that´s it. Like Magic. But I guess there are some restrictions. Like that fact that

1) you can only have one @Execute per class?
2) you can´t use @Inject in a handler?
3) you should only inject into a "method" that can be called right at the start of the application life cycle? (What if that is too early!?! )
4) ???

I guess this whole thing with di will be clearer with time as more and more example code is available on the web, but right now I find it non-intuitive. Can you point me to some place where I can figure out exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named etc) do and do not do?

And btw, You say

Quote:
"4th doesn't make sense at all in a Handler"


Could you please elaborate on why that is? Maybe that would help me understand.

Thanks again,
Karin

PS: The reason why I prefer the global variable-version to the first version, is that method2 does not need to know that method 3 needs a shell in its implementation.

And Ideally method1 also should not have to know about the implementation details of method3.

And that is why I was trying something like my third version, which, as you pointed out, does not compile, but it illustrates what I was expecting form the di - that you can get the info you need whereever you need it.

The 4th version, was a desperate attempt to see if what I wanted to get to work, would indeed work, disregarding the compilation problem. But it din´t since method3 got called way too early.
Re: Dependency Injection: clarification needed [message #544336 is a reply to message #544332] Fri, 02 July 2010 12:10 Go to previous messageGo to next message
Simon Chemouil is currently offline Simon Chemouil
Messages: 24
Registered: July 2009
Junior Member
karins.spam@gmail.com a écrit :
> Hi Tom,
>
> and thanks for the quick response.
> You are correct in that it is a Handler. I wasn´t saying that since I
> didn´t think it was relevant. I thought that the depency injection would
> work in any POJO independently of when/how it was being instantiated.
> I thought the idea of di was that whenever you needed an object, in this
> case a shell, you could just inject the providing service, and that´s
> it. Like Magic. But I guess there are some restrictions. Like that fact
> that
> 1) you can only have one @Execute per class? 2) you can´t use @Inject in
> a handler?

You can use @Inject on any object created using ContextInjectionFactory
or InjectorFactory. All objects created by the E4 framework, such as
classes you define in your model or model fragments (e.g, handlers,
views, ...) are created using the ContextInjectionFactory

Afaik, you can have only one @Execute method (if you have many, only one
will be called and the API doesn't say which, in practice it's the last
one I think). In fact I don't think it's very useful to have more than
one @Execute since you can have as many @Inject as you want

> 3) you should only inject into a "method" that can be called right at
> the start of the application life cycle? (What if that is too early!?! )

By application life cycle, I guess you mean "object creation time",
because UI elements are created lazily (ie, when it's needed, which may
be when you start E4). If it's too early, put the injected object as
@Optional and check for null.

ie:

@CanExecute boolean isValueOK(@Optional @Named("SomeContextVariable")
SomeClass obj) {
return obj != null;
}

You can use @Optional with @Inject'ed methods too.

> 4) ???
> I guess this whole thing with di will be clearer with time as more and
> more example code is available on the web, but right now I find it
> non-intuitive. Can you point me to some place where I can figure out
> exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named
> etc) do and do not do?
> And btw, You say

@CanExecute : only for handlers, whether the @Execute annotated method
can be run or not (the command enablement status, which is repercuted on
menu/toolitems, is linked to this)

@Execute : only for handlers, the method to be executed when the command
is ran

@Inject : ask for injection, that is, provide the objects from the
EclipseContext (by default, model UI items + non-dynamic OSGi services
lookup strategy). You can inject the context and add stuff to it for
injection later too..

ie :
@Inject Constructor(Composite parent, IEclipseContext eclipseContext) {
MyClass obj = ContextInjectionFactory.make(MyClass.class,
eclipseContext); // create a new managed object
eclipseContext.set(MyClass.class, obj); // add the object to the
context for injection later (can be useful)
ContextInjectionFactory.inject(obj, eclipseContext); // keep my
object updated when the context changes (its @Inject methods will be called)
}


@Named : by default the key provided to look up injected objects is the
object's class .getName(), the @Named annotation allows to use another
key (string constant) for this lookup, it's useful if you have several
objects of the same class in the context.

@PostConstruct : called after InjectorFactory.make() (or
ContextInjectionFactory.make)

@PreDestroy : called before .uninject() I think, but I'm not quite sure
when it happens. Use it to clean resources when your object is gonna go away


Hope this helps,

--
Simon
Re: Dependency Injection: clarification needed [message #544347 is a reply to message #544332] Fri, 02 July 2010 12:25 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5434
Registered: July 2009
Senior Member
Hi,

Am 02.07.10 13:50, schrieb karins.spam@gmail.com:
> Hi Tom,
>
> and thanks for the quick response.
> You are correct in that it is a Handler. I wasn´t saying that since I
> didn´t think it was relevant. I thought that the depency injection would
> work in any POJO independently of when/how it was being instantiated.
> I thought the idea of di was that whenever you needed an object, in this
> case a shell, you could just inject the providing service, and that´s
> it. Like Magic. But I guess there are some restrictions. Like that fact
> that
> 1) you can only have one @Execute per class? 2) you can´t use @Inject in
> a handler?

IIRC That's not 100% true you can have multiple and depending on the
context the handler is executed in it will search for the best matching.

> 3) you should only inject into a "method" that can be called right at
> the start of the application life cycle? (What if that is too early!?! )

No you use an @Inject on a method whenever you expect the value to
change and react on it (e.g. updating you UI, ...). You are not
injecting a method.

There are 3 types of injection:
* Constructor (stuff you need on construction) - if you don't expect
the values you get there to change from a runtime overhead this is
best because the framework doesn't has to remember that it injected
something

* Field - if you expect the value to change but you don't need to react
on those changes directly or you don't want to have a
constructor with 100s of arguments (see above that from a performance
PoV Constructor is better).

* Method - if you expect the value to change over time (e.g. the
current workbench selection) and you need to react on the change

> 4) ???
>
> I guess this whole thing with di will be clearer with time as more and
> more example code is available on the web, but right now I find it
> non-intuitive. Can you point me to some place where I can figure out
> exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named
> etc) do and do not do?
> And btw, You say
>

I don't know but here's how to use them:

* In Handlers
@Execute, @CanExecute, @Optional, @Named, @Preference (on an argument
for your @Execute-Method)

* In Parts
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@EventTopic, @Preference

* In Addons
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@EventTopic, @Preference

* In ModelProcessors
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@Execute, @Preference


> Quote:
>> "4th doesn't make sense at all in a Handler"
>
>
> Could you please elaborate on why that is? Maybe that would help me
> understand.

Yes because why should your method be called whenever the active shell
changes? A handler is supposed to run when the user executes a command
and not because some stuff in the context is changing.

That's why @Inject (fields, methods) is not necessarily needed for
Handler-POJOs

If you want to call methods your own you can simply use the
ContextContributionFactory to invoke your methods. Your method cascading
is still not making sense to me or do you expect other to also call an
instance method?

Tom

>
> Thanks again,
> Karin
>
> PS: The reason why I prefer the global variable-version to the first
> version, is that method2 does not need to know that method 3 needs a
> shell in its implementation.
> And Ideally method1 also should not have to know about the
> implementation details of method3.
> And that is why I was trying something like my third version, which, as
> you pointed out, does not compile, but it illustrates what I was
> expecting form the di - that you can get the info you need whereever
> you need it.
> The 4th version, was a desperate attempt to see if what I wanted to get
> to work, would indeed work, disregarding the compilation problem. But
> it din´t since method3 got called way too early.
Re: Dependency Injection: clarification needed [message #544869 is a reply to message #544309] Mon, 05 July 2010 18:06 Go to previous messageGo to next message
Paul Webster is currently offline Paul Webster
Messages: 6859
Registered: July 2009
Location: Ottawa
Senior Member

Tom and Simon have described some of the annotations we use in e4. I'll
just talk a little about what's currently in the system.

@Inject, @PreDestroy, @PostConstruct are part of the object
creation/object initialization cycle for contributed code. In addition,
while the object is "alive" any relevant changes in the context will
cause @Inject methods or fields to be updated.


But we have a more dynamic use of DI in eclipse, specifically targetted
at points where the framework must call contributed code. @Execute,
@CanExecute, @Persist are examples. Unlike the @Inject methods, they
are invoked once by the framework. They involve DI at all so that the
contributed code can access any framework information or services it
needs in a dynamic way. Examples:

@Execute public void execute(IWorkbench workbench,
@Named(IServiceConstants.ACTIVE_SELECTION) IResource selection,
EPartService partService)

@Execute public void execute(EModelService modelService,
MWindow window)

The difference also has to do with use. Contribution code is
instantiated in a context (application, window, part, for example). But
something like a handler will be executed in a context, determined by
the running framework. That's why we don't currently recommend using
@Inject on handlers ... aside from the MApplication, what information
will be available in the execution IEclipseContext? The answer is ...
we're not sure of the best practice ATM, but if you specify it in your
@Execute then you'll probably be getting the appropriate information.

PW


--
Paul Webster
http://wiki.eclipse.org/Platform_Command_Framework
http://wiki.eclipse.org/Command_Core_Expressions
http://wiki.eclipse.org/Menu_Contributions
http://wiki.eclipse.org/Menus_Extension_Mapping
http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse .platform.doc.isv/guide/workbench.htm


Re: Dependency Injection: clarification needed [message #544944 is a reply to message #544309] Tue, 06 July 2010 07:45 Go to previous message
No real name is currently offline No real name
Messages: 13
Registered: June 2010
Junior Member
Thanks a bunch for all the great answers. I will spend some time now writing up an example to try it out, and I´ll let you know if I have any more questions. Thanks again!

Karin
Re: Dependency Injection: clarification needed [message #578397 is a reply to message #544321] Fri, 02 July 2010 11:50 Go to previous message
No real name is currently offline No real name
Messages: 13
Registered: June 2010
Junior Member
Hi Tom,

and thanks for the quick response.

You are correct in that it is a Handler. I wasn´t saying that since I didn´t think it was relevant. I thought that the depency injection would work in any POJO independently of when/how it was being instantiated.

I thought the idea of di was that whenever you needed an object, in this case a shell, you could just inject the providing service, and that´s it. Like Magic. But I guess there are some restrictions. Like that fact that

1) you can only have one @Execute per class?
2) you can´t use @Inject in a handler?
3) you should only inject into a "method" that can be called right at the start of the application life cycle? (What if that is too early!?! )
4) ???

I guess this whole thing with di will be clearer with time as more and more example code is available on the web, but right now I find it non-intuitive. Can you point me to some place where I can figure out exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named etc) do and do not do?

And btw, You say

Quote:
> "4th doesn't make sense at all in a Handler"


Could you please elaborate on why that is? Maybe that would help me understand.

Thanks again,
Karin

PS: The reason why I prefer the global variable-version to the first version, is that method2 does not need to know that method 3 needs a shell in its implementation.

And Ideally method1 also should not have to know about the implementation details of method3.

And that is why I was trying something like my third version, which, as you pointed out, does not compile, but it illustrates what I was expecting form the di - that you can get the info you need whereever you need it.

The 4th version, was a desperate attempt to see if what I wanted to get to work, would indeed work, disregarding the compilation problem. But it din´t since method3 got called way too early.
Re: Dependency Injection: clarification needed [message #578424 is a reply to message #578397] Fri, 02 July 2010 12:10 Go to previous message
Simon Chemouil is currently offline Simon Chemouil
Messages: 24
Registered: July 2009
Junior Member
karins.spam@gmail.com a écrit :
> Hi Tom,
>
> and thanks for the quick response.
> You are correct in that it is a Handler. I wasn´t saying that since I
> didn´t think it was relevant. I thought that the depency injection would
> work in any POJO independently of when/how it was being instantiated.
> I thought the idea of di was that whenever you needed an object, in this
> case a shell, you could just inject the providing service, and that´s
> it. Like Magic. But I guess there are some restrictions. Like that fact
> that
> 1) you can only have one @Execute per class? 2) you can´t use @Inject in
> a handler?

You can use @Inject on any object created using ContextInjectionFactory
or InjectorFactory. All objects created by the E4 framework, such as
classes you define in your model or model fragments (e.g, handlers,
views, ...) are created using the ContextInjectionFactory

Afaik, you can have only one @Execute method (if you have many, only one
will be called and the API doesn't say which, in practice it's the last
one I think). In fact I don't think it's very useful to have more than
one @Execute since you can have as many @Inject as you want

> 3) you should only inject into a "method" that can be called right at
> the start of the application life cycle? (What if that is too early!?! )

By application life cycle, I guess you mean "object creation time",
because UI elements are created lazily (ie, when it's needed, which may
be when you start E4). If it's too early, put the injected object as
@Optional and check for null.

ie:

@CanExecute boolean isValueOK(@Optional @Named("SomeContextVariable")
SomeClass obj) {
return obj != null;
}

You can use @Optional with @Inject'ed methods too.

> 4) ???
> I guess this whole thing with di will be clearer with time as more and
> more example code is available on the web, but right now I find it
> non-intuitive. Can you point me to some place where I can figure out
> exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named
> etc) do and do not do?
> And btw, You say

@CanExecute : only for handlers, whether the @Execute annotated method
can be run or not (the command enablement status, which is repercuted on
menu/toolitems, is linked to this)

@Execute : only for handlers, the method to be executed when the command
is ran

@Inject : ask for injection, that is, provide the objects from the
EclipseContext (by default, model UI items + non-dynamic OSGi services
lookup strategy). You can inject the context and add stuff to it for
injection later too..

ie :
@Inject Constructor(Composite parent, IEclipseContext eclipseContext) {
MyClass obj = ContextInjectionFactory.make(MyClass.class,
eclipseContext); // create a new managed object
eclipseContext.set(MyClass.class, obj); // add the object to the
context for injection later (can be useful)
ContextInjectionFactory.inject(obj, eclipseContext); // keep my
object updated when the context changes (its @Inject methods will be called)
}


@Named : by default the key provided to look up injected objects is the
object's class .getName(), the @Named annotation allows to use another
key (string constant) for this lookup, it's useful if you have several
objects of the same class in the context.

@PostConstruct : called after InjectorFactory.make() (or
ContextInjectionFactory.make)

@PreDestroy : called before .uninject() I think, but I'm not quite sure
when it happens. Use it to clean resources when your object is gonna go away


Hope this helps,

--
Simon
Re: Dependency Injection: clarification needed [message #578435 is a reply to message #578397] Fri, 02 July 2010 12:25 Go to previous message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5434
Registered: July 2009
Senior Member
Hi,

Am 02.07.10 13:50, schrieb karins.spam@gmail.com:
> Hi Tom,
>
> and thanks for the quick response.
> You are correct in that it is a Handler. I wasn´t saying that since I
> didn´t think it was relevant. I thought that the depency injection would
> work in any POJO independently of when/how it was being instantiated.
> I thought the idea of di was that whenever you needed an object, in this
> case a shell, you could just inject the providing service, and that´s
> it. Like Magic. But I guess there are some restrictions. Like that fact
> that
> 1) you can only have one @Execute per class? 2) you can´t use @Inject in
> a handler?

IIRC That's not 100% true you can have multiple and depending on the
context the handler is executed in it will search for the best matching.

> 3) you should only inject into a "method" that can be called right at
> the start of the application life cycle? (What if that is too early!?! )

No you use an @Inject on a method whenever you expect the value to
change and react on it (e.g. updating you UI, ...). You are not
injecting a method.

There are 3 types of injection:
* Constructor (stuff you need on construction) - if you don't expect
the values you get there to change from a runtime overhead this is
best because the framework doesn't has to remember that it injected
something

* Field - if you expect the value to change but you don't need to react
on those changes directly or you don't want to have a
constructor with 100s of arguments (see above that from a performance
PoV Constructor is better).

* Method - if you expect the value to change over time (e.g. the
current workbench selection) and you need to react on the change

> 4) ???
>
> I guess this whole thing with di will be clearer with time as more and
> more example code is available on the web, but right now I find it
> non-intuitive. Can you point me to some place where I can figure out
> exacly what the annotations ((Can)Execute, Inject, PostConstruct, Named
> etc) do and do not do?
> And btw, You say
>

I don't know but here's how to use them:

* In Handlers
@Execute, @CanExecute, @Optional, @Named, @Preference (on an argument
for your @Execute-Method)

* In Parts
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@EventTopic, @Preference

* In Addons
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@EventTopic, @Preference

* In ModelProcessors
@Inject, @PostConstruct, @PreDestroy, @Optional, @Named, @Focus,
@Execute, @Preference


> Quote:
>> "4th doesn't make sense at all in a Handler"
>
>
> Could you please elaborate on why that is? Maybe that would help me
> understand.

Yes because why should your method be called whenever the active shell
changes? A handler is supposed to run when the user executes a command
and not because some stuff in the context is changing.

That's why @Inject (fields, methods) is not necessarily needed for
Handler-POJOs

If you want to call methods your own you can simply use the
ContextContributionFactory to invoke your methods. Your method cascading
is still not making sense to me or do you expect other to also call an
instance method?

Tom

>
> Thanks again,
> Karin
>
> PS: The reason why I prefer the global variable-version to the first
> version, is that method2 does not need to know that method 3 needs a
> shell in its implementation.
> And Ideally method1 also should not have to know about the
> implementation details of method3.
> And that is why I was trying something like my third version, which, as
> you pointed out, does not compile, but it illustrates what I was
> expecting form the di - that you can get the info you need whereever
> you need it.
> The 4th version, was a desperate attempt to see if what I wanted to get
> to work, would indeed work, disregarding the compilation problem. But
> it din´t since method3 got called way too early.
Previous Topic:SimpleIDE example: problem with selection
Next Topic:One Framework to bind them All ?!
Goto Forum:
  


Current Time: Sat Nov 01 03:30:41 GMT 2014

Powered by FUDForum. Page generated in 0.06870 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software