Skip to content

Commit b0c981b

Browse files
committed
Merge branch 'recursive-injection'
This enhances the behavior of context injection to recursively inject @Parameter-annotated fields when the field value is already assigned to an object reference. This is especially useful for CommandModule, which keeps a reference to its delegate Command instance. This Command instance also needs the context injected at the same time it is injected into the CommandModule instance. In the past, a couple of different hacky solutions were employed, such as injecting the context into the Command as part of initialize() -- but each hack had its limitations. The best solution is to actually inject the context into member fields at the same time it is injected into the base object itself. This change ensures that Command instances always receive a context injection immediately, even if e.g. no preprocessing is performed. This branch is dedicated to Richard Domander.
2 parents 3c582e3 + fe04dab commit b0c981b

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

src/main/java/org/scijava/Context.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,11 @@ else if (Context.class.isAssignableFrom(type) && type.isInstance(this)) {
471471
// populate Context parameter
472472
ClassUtils.setValue(f, o, this);
473473
}
474+
else if (!type.isPrimitive()) {
475+
// the parameter is some other object; if it is non-null, we recurse
476+
final Object value = ClassUtils.getValue(f, o);
477+
if (value != null) inject(value);
478+
}
474479
}
475480
catch (final Throwable t) {
476481
handleSafely(t);
@@ -533,7 +538,6 @@ private static PluginIndex plugins(final boolean empty) {
533538
return empty ? new PluginIndex(null) : null;
534539
}
535540

536-
@SuppressWarnings("unchecked")
537541
private static List<Class<? extends Service>> services(final boolean empty) {
538542
if (empty) return Collections.<Class<? extends Service>> emptyList();
539543
return Arrays.<Class<? extends Service>> asList(Service.class);

src/main/java/org/scijava/command/CommandModule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public class CommandModule extends AbstractModule implements Cancelable,
8080
private final CommandInfo info;
8181

8282
/** The command instance handled by this module. */
83+
@Parameter
8384
private final Command command;
8485

8586
@Parameter

src/test/java/org/scijava/command/CommandModuleTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import static org.junit.Assert.assertEquals;
3535
import static org.junit.Assert.assertFalse;
3636
import static org.junit.Assert.assertNotNull;
37+
import static org.junit.Assert.assertSame;
3738
import static org.junit.Assert.assertTrue;
3839

3940
import java.util.concurrent.ExecutionException;
@@ -112,6 +113,20 @@ public void testValidation() throws InterruptedException, ExecutionException {
112113
assertEquals("success", module.getOutput("result"));
113114
}
114115

116+
@Test
117+
public void testCommandInjection() throws InterruptedException,
118+
ExecutionException
119+
{
120+
final Context context = new Context(CommandService.class);
121+
final CommandService commandService = context.service(CommandService.class);
122+
final LogService logService = context.service(LogService.class);
123+
124+
final CommandModule module = //
125+
commandService.run(CommandWithService.class, false).get();
126+
assertSame(logService, module.getInput("log"));
127+
assertTrue((boolean) module.getOutput("success"));
128+
}
129+
115130
// -- Helper classes --
116131

117132
/** A command which implements {@link Cancelable}. */
@@ -235,4 +250,21 @@ public void process(final Module module) {
235250

236251
/** Placeholder class, for type safety. */
237252
public static class Stuff {}
253+
254+
/** A command which has a {@link Service} parameter. */
255+
@Plugin(type = Command.class)
256+
public static class CommandWithService implements Command {
257+
258+
@Parameter
259+
private LogService log;
260+
261+
@Parameter(type = ItemIO.OUTPUT)
262+
private boolean success;
263+
264+
@Override
265+
public void run() {
266+
success = log != null;
267+
}
268+
}
269+
238270
}

0 commit comments

Comments
 (0)