Skip to content

Commit fe4999b

Browse files
committed
2 parents 91829d0 + 41e9319 commit fe4999b

19 files changed

+240
-113
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
<parent>
66
<groupId>org.scijava</groupId>
77
<artifactId>pom-scijava</artifactId>
8-
<version>5.1</version>
8+
<version>5.3.3</version>
99
<relativePath />
1010
</parent>
1111

1212
<artifactId>scijava-common</artifactId>
13-
<version>2.35.2-SNAPSHOT</version>
13+
<version>2.36.1-SNAPSHOT</version>
1414

1515
<name>SciJava Common</name>
1616
<description>SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by both ImageJ and SCIFIO.</description>

src/main/java/org/scijava/AbstractBasicDetails.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ public String toString() {
7171

7272
// -- BasicDetails methods --
7373

74-
@Override
75-
public String getName() {
76-
return name;
77-
}
78-
7974
@Override
8075
public String getLabel() {
8176
return label;
@@ -96,11 +91,6 @@ public String get(final String key) {
9691
return values.get(key);
9792
}
9893

99-
@Override
100-
public void setName(final String name) {
101-
this.name = name;
102-
}
103-
10494
@Override
10595
public void setLabel(final String label) {
10696
this.label = label;
@@ -116,4 +106,16 @@ public void set(String key, String value) {
116106
values.put(key, value);
117107
}
118108

109+
// -- Named methods --
110+
111+
@Override
112+
public String getName() {
113+
return name;
114+
}
115+
116+
@Override
117+
public void setName(final String name) {
118+
this.name = name;
119+
}
120+
119121
}

src/main/java/org/scijava/BasicDetails.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@
3737
*
3838
* @author Curtis Rueden
3939
*/
40-
public interface BasicDetails {
41-
42-
/** Gets the unique name of the object. */
43-
String getName();
40+
public interface BasicDetails extends Named {
4441

4542
/** Gets the name to appear in a UI, if applicable. */
4643
String getLabel();
@@ -54,9 +51,6 @@ public interface BasicDetails {
5451
/** Gets the value of the given key, or null if undefined. */
5552
public String get(String key);
5653

57-
/** Sets the unique name of the object. */
58-
void setName(String name);
59-
6054
/** Sets the name to appear in a UI, if applicable. */
6155
void setLabel(String label);
6256

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

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.scijava.event.ContextDisposingEvent;
4343
import org.scijava.event.EventHandler;
4444
import org.scijava.event.EventService;
45+
import org.scijava.log.LogService;
4546
import org.scijava.plugin.Parameter;
4647
import org.scijava.plugin.PluginIndex;
4748
import org.scijava.service.Service;
@@ -62,10 +63,11 @@ public class Context implements Disposable {
6263

6364
/**
6465
* System property indicating whether the context should fail fast when
65-
* is attempts to instantiate a required service which is invalid or missing.
66+
* attempting to instantiate a required service which is invalid or missing.
6667
* If this property is set to "false" then the context creation will attempt
6768
* to continue even when a required service cannot be instantiated. Otherwise,
68-
* the constructor will throw an {@link IllegalArgumentException} in that situation.
69+
* the constructor will throw an {@link IllegalArgumentException} in that
70+
* situation.
6971
*/
7072
public static final String STRICT_PROPERTY = "scijava.context.strict";
7173

@@ -77,6 +79,23 @@ public class Context implements Disposable {
7779
/** Master index of all plugins known to the application context. */
7880
private final PluginIndex pluginIndex;
7981

82+
/**
83+
* Whether context creation and injection should behave strictly, failing fast
84+
* when attempting to instantiate a required service which is invalid or
85+
* missing.
86+
* <ul>
87+
* <li>If the flag is false, then the context creation will attempt to
88+
* continue even when a required service cannot be instantiated. Otherwise,
89+
* the constructor will throw an {@link IllegalArgumentException} in that
90+
* situation.</li>
91+
* <li>If this flag is false, then a call to {@link Context#inject(Object)}
92+
* will attempt to catch any errors that occur during context injection
93+
* (notably: {@link NoClassDefFoundError} when scanning for event handler
94+
* methods), logging them as errors.</li>
95+
* </ul>
96+
*/
97+
private boolean strict;
98+
8099
/**
81100
* Creates a new SciJava application context with all available services.
82101
*
@@ -239,6 +258,8 @@ public Context(final Collection<Class<? extends Service>> serviceClasses,
239258
this.pluginIndex = pluginIndex == null ? new PluginIndex() : pluginIndex;
240259
this.pluginIndex.discover();
241260

261+
setStrict(strict);
262+
242263
final ServiceHelper serviceHelper =
243264
new ServiceHelper(this, serviceClasses, strict);
244265
serviceHelper.loadServices();
@@ -254,6 +275,14 @@ public PluginIndex getPluginIndex() {
254275
return pluginIndex;
255276
}
256277

278+
public boolean isStrict() {
279+
return strict;
280+
}
281+
282+
public void setStrict(final boolean strict) {
283+
this.strict = strict;
284+
}
285+
257286
/**
258287
* Gets the service of the given class.
259288
*
@@ -329,46 +358,14 @@ public Service getService(final String className) {
329358
*/
330359
public void inject(final Object o) {
331360
// iterate over all @Parameter annotated fields
332-
final List<Field> fields =
333-
ClassUtils.getAnnotatedFields(o.getClass(), Parameter.class);
361+
final List<Field> fields = getParameterFields(o);
334362
for (final Field f : fields) {
335-
f.setAccessible(true); // expose private fields
336-
337-
final Class<?> type = f.getType();
338-
if (Service.class.isAssignableFrom(type)) {
339-
final Service existingService = (Service) ClassUtils.getValue(f, o);
340-
if (existingService != null) {
341-
throw new IllegalStateException("Context already injected: " +
342-
f.getDeclaringClass().getName() + "#" + f.getName());
343-
}
344-
345-
// populate Service parameter
346-
@SuppressWarnings("unchecked")
347-
final Class<? extends Service> serviceType =
348-
(Class<? extends Service>) type;
349-
final Service service = getService(serviceType);
350-
if (service == null && f.getAnnotation(Parameter.class).required()) {
351-
throw new IllegalArgumentException(
352-
createMissingServiceMessage(serviceType));
353-
}
354-
ClassUtils.setValue(f, o, service);
355-
}
356-
else if (Context.class.isAssignableFrom(type) && type.isInstance(this)) {
357-
final Context existingContext = (Context) ClassUtils.getValue(f, o);
358-
if (existingContext != null) {
359-
throw new IllegalStateException("Context already injected: " +
360-
f.getDeclaringClass().getName() + "#" + f.getName());
361-
}
362-
363-
// populate Context parameter
364-
ClassUtils.setValue(f, o, this);
365-
}
363+
inject(f, o);
366364
}
367365

368366
// NB: Subscribe to all events handled by this object.
369367
// This greatly simplifies event handling.
370-
final EventService eventService = getService(EventService.class);
371-
if (eventService != null) eventService.subscribe(o);
368+
subscribeToEvents(o);
372369
}
373370

374371
// -- Disposable methods --
@@ -403,6 +400,75 @@ public static List<Class<? extends Service>> serviceClassList(
403400

404401
// -- Helper methods --
405402

403+
private List<Field> getParameterFields(Object o) {
404+
try {
405+
return ClassUtils.getAnnotatedFields(o.getClass(), Parameter.class);
406+
}
407+
catch (final Throwable t) {
408+
handleSafely(t);
409+
}
410+
return Collections.emptyList();
411+
}
412+
413+
private void inject(final Field f, final Object o) {
414+
try {
415+
f.setAccessible(true); // expose private fields
416+
417+
final Class<?> type = f.getType();
418+
if (Service.class.isAssignableFrom(type)) {
419+
final Service existingService = (Service) ClassUtils.getValue(f, o);
420+
if (existingService != null) {
421+
throw new IllegalStateException("Context already injected: " +
422+
f.getDeclaringClass().getName() + "#" + f.getName());
423+
}
424+
425+
// populate Service parameter
426+
@SuppressWarnings("unchecked")
427+
final Class<? extends Service> serviceType =
428+
(Class<? extends Service>) type;
429+
final Service service = getService(serviceType);
430+
if (service == null && f.getAnnotation(Parameter.class).required()) {
431+
throw new IllegalArgumentException(
432+
createMissingServiceMessage(serviceType));
433+
}
434+
ClassUtils.setValue(f, o, service);
435+
}
436+
else if (Context.class.isAssignableFrom(type) && type.isInstance(this)) {
437+
final Context existingContext = (Context) ClassUtils.getValue(f, o);
438+
if (existingContext != null) {
439+
throw new IllegalStateException("Context already injected: " +
440+
f.getDeclaringClass().getName() + "#" + f.getName());
441+
}
442+
443+
// populate Context parameter
444+
ClassUtils.setValue(f, o, this);
445+
}
446+
}
447+
catch (final Throwable t) {
448+
handleSafely(t);
449+
}
450+
}
451+
452+
private void subscribeToEvents(final Object o) {
453+
try {
454+
final EventService eventService = getService(EventService.class);
455+
if (eventService != null) eventService.subscribe(o);
456+
}
457+
catch (final Throwable t) {
458+
handleSafely(t);
459+
}
460+
}
461+
462+
private void handleSafely(final Throwable t) {
463+
if (isStrict()) {
464+
// NB: Only rethrow unchecked exceptions.
465+
if (t instanceof RuntimeException) throw (RuntimeException) t;
466+
if (t instanceof Error) throw (Error) t;
467+
}
468+
final LogService log = getService(LogService.class);
469+
if (log != null) log.error(t);
470+
}
471+
406472
private String createMissingServiceMessage(
407473
final Class<? extends Service> serviceType)
408474
{

src/main/java/org/scijava/MenuEntry.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* @author Curtis Rueden
4040
* @author Johannes Schindelin
4141
*/
42-
public class MenuEntry {
42+
public class MenuEntry implements Named {
4343

4444
public static final double DEFAULT_WEIGHT = Double.POSITIVE_INFINITY;
4545

@@ -68,14 +68,6 @@ public MenuEntry(final String name, final double weight,
6868
setIconPath(iconPath);
6969
}
7070

71-
public void setName(final String name) {
72-
this.name = name;
73-
}
74-
75-
public String getName() {
76-
return name;
77-
}
78-
7971
public void setWeight(final double weight) {
8072
this.weight = weight;
8173
}
@@ -120,6 +112,20 @@ public void assignProperties(final MenuEntry entry) {
120112
if (iconPath == null) iconPath = entry.getIconPath();
121113
}
122114

115+
// -- Named methods --
116+
117+
@Override
118+
public String getName() {
119+
return name;
120+
}
121+
122+
@Override
123+
public void setName(final String name) {
124+
this.name = name;
125+
}
126+
127+
// -- Object methods --
128+
123129
@Override
124130
public String toString() {
125131
return name;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava;
33+
34+
/**
35+
* Interface for things that have names.
36+
*
37+
* @author Lee Kamentsky
38+
*/
39+
public interface Named {
40+
41+
/** Gets the name of the object. */
42+
String getName();
43+
44+
/** Sets the name of the object. */
45+
void setName(String name);
46+
47+
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,6 @@ public List<T> getChoices() {
167167

168168
// -- BasicDetails methods --
169169

170-
@Override
171-
public String getName() {
172-
return field.getName();
173-
}
174-
175170
@Override
176171
public String getLabel() {
177172
return getParameter().label();
@@ -198,4 +193,11 @@ public String get(final String key) {
198193
return null;
199194
}
200195

196+
// -- Named methods --
197+
198+
@Override
199+
public String getName() {
200+
return field.getName();
201+
}
202+
201203
}

0 commit comments

Comments
 (0)