Callbacks and @Parameter persistence

Tags: #<Tag:0x00007fb882c2e2b8> #<Tag:0x00007fb882c2df48> #<Tag:0x00007fb882c2dcc8>


Hi all,

I have situation

@Plugin(type = Command.class)
public class MyPlugin extends ContextCommand {
    @Parameter(persist = true, callback = "changeOtherVariable")
    private long variable;

    private long otherVariable;

    private void changeOtherVariable() {
       otherVariable = variable + 1;

Now, how do I set otherVariable initially based on the saved value of variable? An initializer is apparently called before the saved value is loaded, and a callback is called only when user changes the value. Callback doesn’t happen when the saved value is loaded. I have also tried implementing Previewable, but preview() doesn’t get called before any widget values are changed either.

Best regards,


Firstly, note that the default value of persist is true, so writing persist = true is redundant. If you do not want otherVariable to cache previous values, you should add persist = false to its annotation.

I think that as the code stands right now, you cannot do it in an intuitive manner. :slight_frown:

Saved variable values are restored during the module preprocessing pipeline, by the LoadInputsPreprocessor, which runs at priority VERY_LOW - 1. But module and individual parameter initializers are called by the InitPreprocessor, which runs at HIGH. So persisted values get loaded after variables are initialized. For this reason, a very common pattern in the code right now is persist = false, initializer = "...", since otherwise, the initializer is not very useful.

One workaround you could use is to assign an initializer to the command, and then in that initializer method, load the desired persisted value(s) and assign them to the proper variables. Here is a working first cut at that:

import org.scijava.command.ContextCommand;
import org.scijava.command.Command;
import org.scijava.command.CommandService;
import org.scijava.convert.ConvertService;
import org.scijava.module.ModuleItem;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.prefs.PrefService;

@Plugin(type = Command.class, initializer = "initParameters")
public class MyPlugin extends ContextCommand {
    private CommandService commandService;

	private PrefService prefs;

	private ConvertService convertService;

    @Parameter(callback = "changeOtherVariable")
    private long variable;

    @Parameter(persist = false)
    private long otherVariable;

    private void initParameters() {
        // load previous persisted value
    	final String sValue = prefs.get(getClass(), "variable");
    	if (sValue != null) variable = convertService.convert(sValue, long.class);
        // sync dependent variable to match

    private void changeOtherVariable() {
        otherVariable = variable + 1;
    public void run() {
    	System.out.println("variable = " + variable + ", otherVariable = " + otherVariable);


Cheers, this worked perfectly! :thumbsup:


Just out of curiosity, why this instead of Long.valueOf(sValue)?


The convert service is extensible. So you could, for example, implement conversion of an alternate string format into a long as a new converter, and the convertService.convert(sValue, long.class) would magically support it, where as Long.valueOf(String) can never be extended to new syntaxes.