2929package org .scijava .ops ;
3030
3131import java .lang .reflect .Field ;
32+ import java .lang .reflect .Method ;
33+ import java .lang .reflect .ParameterizedType ;
3234import java .lang .reflect .Type ;
3335import java .lang .reflect .TypeVariable ;
3436import java .util .ArrayList ;
4547import org .scijava .log .LogService ;
4648import org .scijava .ops .core .Op ;
4749import org .scijava .ops .core .OpCollection ;
50+ import org .scijava .ops .matcher .MatchingUtils ;
51+ import org .scijava .ops .matcher .MatchingUtils .TypeInferenceException ;
4852import org .scijava .ops .matcher .OpCandidate ;
4953import org .scijava .ops .matcher .OpClassInfo ;
5054import org .scijava .ops .matcher .OpFieldInfo ;
5155import org .scijava .ops .matcher .OpInfo ;
5256import org .scijava .ops .matcher .OpMatchingException ;
57+ import org .scijava .ops .matcher .OpMethodInfo ;
5358import org .scijava .ops .matcher .OpRef ;
5459import org .scijava .ops .matcher .OpTypeMatchingService ;
5560import 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- "\n Op class: " + op . opInfo () .implementationName () + //
247+ "\n Op class: " + opInfo .implementationName () + //
215248 "\n Dependency identifier: " + dependency .getKey () + //
216249 "\n \n Attempted request:\n " + inferredRef , e );
217250 }
0 commit comments