Skip to content

Commit aa2bf76

Browse files
committed
ObjectIndex: only resolve relevant pending objects
If a pending object will not be of a type compatible with the requested type, then skip resolution of that pending object. This improves performance of the get(Class) and getAll() methods in cases where there are a large number of pending objects in the index. It also helps to eliminate difficulties like those in issue #90.
1 parent 149eae8 commit aa2bf76

File tree

1 file changed

+45
-4
lines changed

1 file changed

+45
-4
lines changed

src/main/java/org/scijava/object/ObjectIndex.java

+45-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
package org.scijava.object;
3333

34+
import java.lang.reflect.Method;
35+
import java.lang.reflect.Type;
3436
import java.util.ArrayList;
3537
import java.util.Collection;
3638
import java.util.Collections;
@@ -45,6 +47,7 @@
4547
import java.util.concurrent.ConcurrentHashMap;
4648

4749
import org.scijava.util.ClassUtils;
50+
import org.scijava.util.GenericUtils;
4851

4952
/**
5053
* Data structure for managing lists of registered objects.
@@ -129,7 +132,7 @@ public List<E> getAll() {
129132
*/
130133
public List<E> get(final Class<?> type) {
131134
// lazily register any pending objects
132-
if (!pending.isEmpty()) resolvePending();
135+
if (!pending.isEmpty()) resolvePending(type);
133136

134137
List<E> list = retrieveList(type);
135138
// NB: Return a copy of the data, to facilitate thread safety.
@@ -380,15 +383,53 @@ protected List<E> retrieveList(final Class<?> type) {
380383
return list;
381384
}
382385

383-
private void resolvePending() {
386+
private void resolvePending(final Class<?> type) {
384387
synchronized (pending) {
385-
while (!pending.isEmpty()) {
386-
final LazyObjects<? extends E> c = pending.remove(0);
388+
for (int p = pending.size() - 1; p >= 0; p--) {
389+
final LazyObjects<? extends E> c = pending.get(p);
390+
391+
// NB: If this pending callback returns objects of a different
392+
// type than the one we are interested in, it can be skipped.
393+
if (!isCompatibleType(c, type)) continue;
394+
395+
// trigger the callback and add the results
396+
pending.remove(p);
387397
addAll(c.get());
388398
}
389399
}
390400
}
391401

402+
// -- Helper methods --
403+
404+
private boolean isCompatibleType(final LazyObjects<? extends E> c,
405+
final Class<?> type)
406+
{
407+
if (type == All.class) return true;
408+
409+
// extract the generic type from the LazyObjects#get return type
410+
final Method getMethod;
411+
try {
412+
getMethod = c.getClass().getMethod("get");
413+
}
414+
catch (final NoSuchMethodException exc) {
415+
throw new IllegalStateException(exc);
416+
}
417+
final Type returnType =
418+
GenericUtils.getMethodReturnType(getMethod, c.getClass());
419+
final Type paramType =
420+
GenericUtils.getTypeParameter(returnType, Collection.class, 0);
421+
422+
// NB: paramType will be null if the LazyObjects subtype uses raw types.
423+
if (paramType != null) {
424+
final Class<?> paramClass = GenericUtils.getClass(paramType);
425+
if (paramClass != null && !paramClass.isAssignableFrom(type)) {
426+
return false;
427+
}
428+
}
429+
430+
return true;
431+
}
432+
392433
// -- Helper classes --
393434

394435
private static class All {

0 commit comments

Comments
 (0)