Bug 391061 - superfluous @Inject from @Preference
Summary: superfluous @Inject from @Preference
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Runtime (show other bugs)
Version: 4.2.1   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 4.4 M7   Edit
Assignee: Paul Webster CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted
Depends on:
Blocks:
 
Reported: 2012-10-03 15:13 EDT by Ferry Huberts CLA
Modified: 2014-04-30 09:30 EDT (History)
13 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ferry Huberts CLA 2012-10-03 15:13:31 EDT
Opening a dialog in a handler to get a username and password and put it into prefs (part of a tutorial by Lars) by using this code:

public class EnterCredentialsHandler {
	@Inject
	@Preference(nodePath = "com.example.e4.rcp.todo", value = "user")
	String userPref;
	@Inject
	@Preference(nodePath = "com.example.e4.rcp.todo", value = "password")
	String passwordPref;

	@Execute
	public void execute(Shell shell, @Preference(nodePath = "com.example.e4.rcp.todo") IEclipsePreferences prefs) {
		PasswordDialog dialog = new PasswordDialog(shell);

		if (userPref != null) {
			dialog.setUser(userPref);
		}

		if (passwordPref != null) {
			dialog.setPassword(passwordPref);
		}

		if (dialog.open() == Window.OK) {
			System.out.println("change user now");
			prefs.put("user", dialog.getUser());
			System.out.println("change password now");
			prefs.put("password", dialog.getPassword());
			try {
				System.out.println("flush now");
				prefs.flush();
			} catch (BackingStoreException e) {
			}
		}
	}
}

And listening to it by using this code (in a Part):

	@Inject
	@Optional
	public void trackUser(
		@Preference(nodePath = "com.example.e4.rcp.todo", value = "user") String user) {
		System.out.println("User = " + user);
	}

	@Inject
	@Optional
	public void trackPassword(
		@Preference(nodePath = "com.example.e4.rcp.todo", value = "password") String password) {
		System.out.println("Pwd  = " + password);
	}


The previously persisted values of user/password are aa/bb.
Now, by means of the dialog, I set them to aaa/bbb

This results in the following output:

		change user now
		User = aaa
		Pwd  = bb
		change password now
		User = aaa
		Pwd  = bbb
		flush now

To me that is quite unexpected. It seems that pwd is incorrectly injected when the user is changed. pwd did not change. The same when pwd is changed but now for the user.

I would have expected the following output:

		change user now
		User = aaa
		change password now
		Pwd  = bbb
		flush now

IMHO this is (at least) a performance issue.
Comment 1 Ferry Huberts CLA 2012-10-03 15:16:10 EDT
PS. I'm on Juno SR1.
Comment 2 Ferry Huberts CLA 2012-11-11 06:57:33 EST
ping?
Comment 3 Paul Webster CLA 2012-11-12 09:50:02 EST
No one is looking at this component at the moment, but I'd accept patches.  http://wiki.eclipse.org/Platform_UI/How_to_Contribute

My guess would be that it's done in the org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier in org.eclipse.e4.core.di.extensions

PW
Comment 4 Eric Moffatt CLA 2013-09-06 10:21:36 EDT
Perhaps Paul Elder could take a look at this when we gets back to looking into DI issues...
Comment 5 Dani Megert CLA 2013-11-05 02:41:26 EST
Moving target milestone since M3 has been delivered.
Comment 6 Dani Megert CLA 2014-01-14 09:19:54 EST
Removing target milestone since no one seems to be interested in fixing this at the moment.
Comment 7 Steven Spungin CLA 2014-04-15 18:31:14 EDT
OMG.  A year and a half and still not fixed.  Does anybody even use preference injection?

The internal problem is the object getting injected is the class, not the method.  The class injector has no way of knowing that a 'preference' is getting injected, and cannot refer to the nodePath or the key to know what methods to call; so every time a preference changes, every method and member gets reinjected.  Performance is exponential as more methods are added. Dealing with intermediate values is difficult to say the least.

My solution was to add a callback interface and a new method in IRequestor.

static public interface AllowInjectionCallback {
		boolean allowInjection(Object location, Object userObject, Object actualArgs);
	}

public Object execute(AllowInjectionCallback allowInjectionCallback) throws InjectionException;

I updated all IRequestor implementations to call execute(null) from execute.  A null callback  has the original implementation, so nothing changes unless an actual handler is sent into the method.

The end result is that PreferencesObjectSupplier can now call execute on the object, and veto all annotated methods that do not match the nodePath/key.  We can extend this to do the same for members, constructor, etc.

I will post the patch as soon as I confirm it does not break anything.
Comment 8 Steven Spungin CLA 2014-04-16 01:05:31 EDT
https://git.eclipse.org/r/#/c/25095/
Comment 9 Paul Webster CLA 2014-04-16 16:46:31 EDT
It looks like the problem is we add a listener per (nodePath,requestor) instead of a listener per (nodePath, key, requestor).

Why not add the key to the org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.PrefInjectionListener and allow that to filter the PreferenceChangeEvent?

PW
Comment 10 Steven Spungin CLA 2014-04-16 22:13:34 EDT
(In reply to Paul Webster from comment #9)
> It looks like the problem is we add a listener per (nodePath,requestor)
> instead of a listener per (nodePath, key, requestor).
> 
> Why not add the key to the
> org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.
> PrefInjectionListener and allow that to filter the PreferenceChangeEvent?
> 
> PW

That would result in more listeners, but certainly is a viable option.  I'll git to it.

Are you OK with having a hash table for each nodePath, or a hash of nodepath/key and a single table?
Comment 12 Ferry Huberts CLA 2014-04-17 17:11:07 EDT
(In reply to Paul Webster from comment #11)
> Released as
> http://git.eclipse.org/c/platform/eclipse.platform.runtime.git/commit/
> ?id=13042ba9d212d3eae79459c631953f8d9f03b73d
> 
> Thanks Steven.
> 
> PW

thanks guys.
nice solution
Comment 13 Paul Webster CLA 2014-04-30 07:26:45 EDT
In 4.4.0.I20140428-2000

Ferry, could you please verify it works for your scenario as well? Thanks.

PW
Comment 14 Ferry Huberts CLA 2014-04-30 08:40:06 EDT
(In reply to Paul Webster from comment #13)
> In 4.4.0.I20140428-2000
> 
> Ferry, could you please verify it works for your scenario as well? Thanks.
> 
> PW

Well, if you ran the reproducer given in comment 1 then I'm ok with it.

I'm seriously low on time at the moment. sorry.

If you tell me where to get a build with the fix in it, I'll try to squeeze in a check. no promises :-(
Comment 15 Paul Webster CLA 2014-04-30 09:18:08 EDT
If you use an SDK, http://download.eclipse.org/eclipse/downloads/drops4/I20140429-2000/

If you use one of the EPP from http://www.eclipse.org/downloads/index-developer.php it would have to wait for another 1.5 weeks.

It's OK if it takes 2 weeks, I've already verified it works at this end, but the confirmation from the reporter is still important.  Thanks for what you can do.

PW
Comment 16 Steven Spungin CLA 2014-04-30 09:26:26 EDT
(In reply to Ferry Huberts from comment #14)
> (In reply to Paul Webster from comment #13)
> > In 4.4.0.I20140428-2000
> > 
> > Ferry, could you please verify it works for your scenario as well? Thanks.
> > 
> > PW
> 
> Well, if you ran the reproducer given in comment 1 then I'm ok with it.
> 
> I'm seriously low on time at the moment. sorry.
> 
> If you tell me where to get a build with the fix in it, I'll try to squeeze
> in a check. no promises :-(

I pulled down latest integration and confirmed expected result from comment #1.
Comment 17 Paul Webster CLA 2014-04-30 09:28:44 EDT
OK, thanks guys.

PW
Comment 18 Ferry Huberts CLA 2014-04-30 09:30:07 EDT
Thanks Steven, you saved me some time :-)