Skip to content

Commit 600bd5a

Browse files
committed
Add Op method indexing and dependency resolution
TODO: Dependency resolution needs some extra type inference steps at the moment. Why? Can we get rid of this?
1 parent f3089de commit 600bd5a

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/main/java/org/scijava/ops/OpService.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
package org.scijava.ops;
3030

3131
import java.lang.reflect.Field;
32+
import java.lang.reflect.Method;
33+
import java.lang.reflect.ParameterizedType;
3234
import java.lang.reflect.Type;
3335
import java.lang.reflect.TypeVariable;
3436
import java.util.ArrayList;
@@ -45,11 +47,14 @@
4547
import org.scijava.log.LogService;
4648
import org.scijava.ops.core.Op;
4749
import org.scijava.ops.core.OpCollection;
50+
import org.scijava.ops.matcher.MatchingUtils;
51+
import org.scijava.ops.matcher.MatchingUtils.TypeInferenceException;
4852
import org.scijava.ops.matcher.OpCandidate;
4953
import org.scijava.ops.matcher.OpClassInfo;
5054
import org.scijava.ops.matcher.OpFieldInfo;
5155
import org.scijava.ops.matcher.OpInfo;
5256
import org.scijava.ops.matcher.OpMatchingException;
57+
import org.scijava.ops.matcher.OpMethodInfo;
5358
import org.scijava.ops.matcher.OpRef;
5459
import org.scijava.ops.matcher.OpTypeMatchingService;
5560
import org.scijava.ops.transform.OpRunner;
@@ -123,11 +128,20 @@ public void initOpCache() {
123128
// Add Ops contained in an OpCollection
124129
for (final PluginInfo<OpCollection> pluginInfo : pluginService.getPluginsOfType(OpCollection.class)) {
125130
try {
126-
final List<Field> fields = ClassUtils.getAnnotatedFields(pluginInfo.loadClass(), OpField.class);
131+
final Class<? extends OpCollection> opCollectionClass = pluginInfo
132+
.loadClass();
133+
final List<Field> fields = ClassUtils.getAnnotatedFields(
134+
opCollectionClass, OpField.class);
127135
for (Field field : fields) {
128136
OpInfo opInfo = new OpFieldInfo(field);
129137
addToCache(opInfo, field.getAnnotation(OpField.class).names());
130138
}
139+
final List<Method> methods = ClassUtils.getAnnotatedMethods(
140+
opCollectionClass, OpMethod.class);
141+
for (final Method method : methods) {
142+
OpInfo opInfo = new OpMethodInfo(method);
143+
addToCache(opInfo, method.getAnnotation(OpMethod.class).names());
144+
}
131145
} catch (InstantiableException exc) {
132146
log.error("Can't load class from plugin info: " + pluginInfo.toString(), exc);
133147
}
@@ -191,13 +205,32 @@ public LogService logger() {
191205
private List<Object> resolveOpDependencies(OpCandidate op)
192206
throws OpMatchingException
193207
{
194-
final List<OpDependencyMember<?>> dependencies = op.opInfo().dependencies();
208+
final OpInfo opInfo = op.opInfo();
209+
final List<OpDependencyMember<?>> dependencies = opInfo.dependencies();
195210
final List<Object> resolvedDependencies = new ArrayList<>(dependencies
196211
.size());
197212
for (final OpDependencyMember<?> dependency : dependencies) {
198213
final String dependencyName = dependency.getDependencyName();
214+
Map<TypeVariable<?>, Type> typeVarAssigns = op.typeVarAssigns();
215+
if (opInfo instanceof OpMethodInfo) {
216+
// TODO: Avoid treating Op methods differently here.
217+
final Type opType = opInfo.opType();
218+
if (opType instanceof ParameterizedType) {
219+
typeVarAssigns = new HashMap<>(typeVarAssigns);
220+
final Type[] declaredOpParamTypes = ((ParameterizedType) opType)
221+
.getActualTypeArguments();
222+
final Type[] actualOpParamTypes = op.getRef().getArgs();
223+
try {
224+
MatchingUtils.inferTypeVariables(declaredOpParamTypes,
225+
actualOpParamTypes, typeVarAssigns);
226+
}
227+
catch (TypeInferenceException exc) {
228+
// Ignore, matching will probably fail anyway. But let's try.
229+
}
230+
}
231+
}
199232
final Type mappedDependencyType = Types.mapVarToTypes(new Type[] {
200-
dependency.getType() }, op.typeVarAssigns())[0];
233+
dependency.getType() }, typeVarAssigns)[0];
201234
final OpRef inferredRef = inferOpRef(mappedDependencyType, dependencyName,
202235
op.typeVarAssigns());
203236
if (inferredRef == null) {
@@ -211,7 +244,7 @@ private List<Object> resolveOpDependencies(OpCandidate op)
211244
catch (final Exception e) {
212245
throw new OpMatchingException(
213246
"Could not find Op that matches requested Op dependency:" +
214-
"\nOp class: " + op.opInfo().implementationName() + //
247+
"\nOp class: " + opInfo.implementationName() + //
215248
"\nDependency identifier: " + dependency.getKey() + //
216249
"\n\n Attempted request:\n" + inferredRef, e);
217250
}

src/main/java/org/scijava/ops/matcher/MatchingUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ public static boolean isSafeAssignable(Type[] destTypes, Map<TypeVariable<?>, Ty
388388
/**
389389
* Exception indicating that type vars could not be inferred.
390390
*/
391-
private static class TypeInferenceException extends Exception {
391+
public static class TypeInferenceException extends Exception {
392392
/**
393393
*
394394
*/
@@ -422,7 +422,7 @@ private static <M> boolean containsNull(M[] arr) {
422422
* @param typeAssigns
423423
* @throws TypeInferenceException
424424
*/
425-
private static void inferTypeVariables(Type[] types, Type[] inferFrom, Map<TypeVariable<?>, Type> typeAssigns)
425+
public static void inferTypeVariables(Type[] types, Type[] inferFrom, Map<TypeVariable<?>, Type> typeAssigns)
426426
throws TypeInferenceException {
427427
if (typeAssigns == null)
428428
throw new IllegalArgumentException();

0 commit comments

Comments
 (0)