Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Injection and SWT(Is there a better way?)
Injection and SWT [message #1017300] Mon, 11 March 2013 14:33 Go to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

Thanks to everyone for previous injection suggestions. I've been trying to percolate injection down into my SWT layers. I've come up with a pattern to migrate my legacy code to. It seems a bit cumbersome, though, and I wondered if there was something more svelte.

So we have class A, which has been appropriately constructed and has access to an IEclipseContext. It wishes to contract class B, which extends a SWT Composite.

Previously:

Class A:
....
   B mBCtrl = new B(this, SWT.NULL);


class B extends Composite {
...
  public void B(Composite parent, int style) {
    super(parent, style);
    // some more stuff



I've been migrating this to this pattern:

Class A:
....
   B mBCtrl = new B(this, SWT.NULL);
   ContextInjectFactory.inject(mBCtrl, mContext);


class B extends Composite {
...
  public void B(Composite parent, int style) {
    super(parent, style);
  }
  @PostConstruct
  public void init() {
    // some more stuff



It works. But I'm not entirely happy with the verbosity of it. It isn't as "clean" as previously. Additionally I'm concerned that it is error prone. As I build this out into my code, if I forget to change one instance of construction, it will not catch it at compile time, and the symptom at run time will be a blank control or a NPE on something that was supposed to have been injected.

I don't suppose there is a way to "construct and inject"? E.g.

mBCtrl = (B)ContextInjectionFactory.make(mContext, B.class, parent, style);


I guess I could write a helper function to do this. Should I do that, or am I missing a better approach?


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Injection and SWT [message #1017307 is a reply to message #1017300] Mon, 11 March 2013 14:54 Go to previous messageGo to next message
Christoph Keimel is currently offline Christoph KeimelFriend
Messages: 384
Registered: December 2010
Location: Germany
Senior Member
There is a CIF.make function. To have the injection work, you need to supply to the parameters. The pattern could look something like this:

class A {
	B createB(Composite parent, IEclispeContext context) {
		IEclipseContext childContext = context.createChild();
		childContext.set(Composite.class, parent);
		childContext.set("style", SWT.None);
		
		B mBCtrl = ContextInjectFactory.make(B.class, childContext);;
		mBCtrl.addDisposeListener(new DisposeListener() {
			@Override
			public void widgetDisposed(DisposeEvent e) {
				childContext.dispose();
			}
		});
		return mBCtrl;
	}
}

class B extends Composite {
	@Inject
	B(Composite parent, @Named("style") int style) {
		super(parent, style);
	}
}

Re: Injection and SWT [message #1017324 is a reply to message #1017307] Mon, 11 March 2013 15:24 Go to previous message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

We have to dispose child contexts? Erk. I didn't know that. That adds a wrinkle. Thanks for pointing that out, Christopher.
I like the way you annotate the constructor. That is much cleaner. I'm leaning much more towards a helper function now. I think I can make things much more clean. So, with a helper function that takes the class, the context, and then a variable length argument of pairs to add to the context, it can slim down to this:

Class A:
....
   B mBCtrl = ContextInjectionHelper.make(B.class, context, "parent", this, "style", SWT.NULL);


class B extends Composite {
...
  @Inject
  public void B(@Named("parent") Composite parent, @Named("style") int style) {
    super(parent, style);
    // some more stuff


Which is, pretty much, no additional lines of code. And it should detect a bad call at compile time. Much better!
Here is the helper code:

    public static <T> T make(Class<T> clazz, IEclipseContext context, Object... subContextElements)
    {
        T o;
        if (subContextElements.length == 0)
            o = (T)ContextInjectionFactory.make(clazz, context);
        else
        {
            if ((subContextElements.length%2) != 0)
                throw new IllegalArgumentException("Expected even number of context element pairs!");
            final EclipseContext subContext = new EclipseContext(context);
            for (int i = 0; i < subContextElements.length; i += 2)
                if (subContextElements[i] instanceof String)
                    subContext.set((String)subContextElements[i+0], subContextElements[i+1]);
                else if (subContextElements[i] instanceof Class<?>)
                    subContext.set((Class)subContextElements[i+0], subContextElements[i+1]);
            o = (T)ContextInjectionFactory.make(clazz, subContext);
            if (o instanceof Control)
                ((Control)o).addDisposeListener(new DisposeListener() {                    
                    @Override
                    public void widgetDisposed(DisposeEvent ev)
                    {
                        subContext.dispose();
                    }
                });
            //else object must take care of disposing context
        }
        return o;
    }


It would be nifty to see this in ContextInjectionFactory, but I think it adds too many constraints to go into core code.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Previous Topic:No events received in 4.2.2
Next Topic:Prompting before closing Stopped working
Goto Forum:
  


Current Time: Sun Nov 23 20:23:46 GMT 2014

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

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