Dependency Injection: clarification needed [message #578349] |
Fri, 02 July 2010 10:03 |
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 #578374 is a reply to message #578349] |
Fri, 02 July 2010 10:57 |
Thomas Schindl Messages: 6651 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 #578503 is a reply to message #578349] |
Mon, 05 July 2010 18:06 |
|
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
Paul Webster
http://wiki.eclipse.org/Platform_Command_Framework
http://wiki.eclipse.org/Command_Core_Expressions
http://wiki.eclipse.org/Menu_Contributions
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03859 seconds