Skip to content

Commit 7f2790c

Browse files
committed
Create struct for OpAdaptationInfo
TODO: Resolve createOpInstance
1 parent 021c79a commit 7f2790c

7 files changed

Lines changed: 151 additions & 15 deletions

File tree

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,7 @@ public Object findOpInstance(final String opName, final OpRef ref, boolean adapt
297297
} catch (OpMatchingException e) {
298298
throw new IllegalArgumentException(e);
299299
}
300-
// TODO: THIS IS WRONG! We need the OpInfo of the output of the adaptation!
301-
// This gives the OpInfo of the original (unadapted) op!
302-
OpInfo adaptedInfo = adaptation == null ? null : adaptation.srcInfo();
300+
OpInfo adaptedInfo = adaptation == null ? null : adaptation.opInfo();
303301
Object wrappedOp = wrapOp(op, match, adaptedInfo);
304302
return wrappedOp;
305303
}
@@ -338,12 +336,13 @@ private AdaptedOp adaptOp(OpRef ref) throws OpMatchingException {
338336
final Object fromOp = srcCandidate.opInfo().createOpInstance(srcDependencies).object();
339337

340338
// get adapted Op by applying adaptor on unadapted Op, then return
341-
// TODO: create OpInfo for transformed Op (everything the same except
342-
// types/param IO status)
343339
// TODO: can we make this safer?
344340
@SuppressWarnings("unchecked")
345341
Object toOp = ((Function<Object, Object>) adaptorOp).apply(fromOp);
346-
return new AdaptedOp(toOp, srcCandidate.opInfo(), adaptor.opInfo());
342+
// construct type of adapted op
343+
Type opType = Types.substituteTypeVariables(adaptor.opInfo().output().getType(),
344+
srcCandidate.typeVarAssigns());
345+
return new AdaptedOp(toOp, opType, srcCandidate.opInfo(), adaptor.opInfo());
347346
} catch (OpMatchingException e1) {
348347
continue;
349348
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package org.scijava.ops.matcher;
2+
3+
import java.lang.reflect.AnnotatedElement;
4+
import java.lang.reflect.Type;
5+
import java.util.List;
6+
7+
import org.scijava.ops.OpUtils;
8+
import org.scijava.param.ParameterStructs;
9+
import org.scijava.param.ValidityException;
10+
import org.scijava.struct.Struct;
11+
import org.scijava.struct.StructInstance;
12+
13+
/**
14+
* {@link OpInfo} for ops that have been adapted to some other Op type.
15+
*
16+
* @author Gabriel Selzer
17+
*
18+
*/
19+
public class OpAdaptationInfo implements OpInfo {
20+
21+
private OpInfo srcInfo;
22+
private Type type;
23+
24+
private Struct struct;
25+
private ValidityException validityException;
26+
27+
public OpAdaptationInfo(OpInfo srcInfo, Type type) {
28+
this.srcInfo = srcInfo;
29+
this.type = type;
30+
31+
// NOTE: since the source Op has already been shown to be valid, there is not
32+
// much for us to do here.
33+
try {
34+
struct = ParameterStructs.structOf(srcInfo, type);
35+
OpUtils.checkHasSingleOutput(struct);
36+
} catch (ValidityException e) {
37+
validityException = e;
38+
}
39+
}
40+
41+
@Override
42+
public Type opType() {
43+
return type;
44+
}
45+
46+
@Override
47+
public Struct struct() {
48+
// TODO Can we build this struct?
49+
return struct;
50+
}
51+
52+
// we want the original op to have priority over this one.
53+
@Override
54+
public double priority() {
55+
return srcInfo.priority() - 1;
56+
}
57+
58+
@Override
59+
public String implementationName() {
60+
return srcInfo.implementationName();
61+
}
62+
63+
@Override
64+
public StructInstance<?> createOpInstance(List<?> dependencies) {
65+
// TODO: does this method make sense for this kind of Op? It really doesn't have
66+
// any dependencies...if so, we should implement this method.
67+
throw new UnsupportedOperationException(
68+
"StructInstance unavailable for adaptation of " + srcInfo.implementationName());
69+
70+
}
71+
72+
@Override
73+
public boolean isValid() {
74+
return validityException == null;
75+
}
76+
77+
@Override
78+
public ValidityException getValidityException() {
79+
return validityException;
80+
}
81+
82+
@Override
83+
public AnnotatedElement getAnnotationBearer() {
84+
return srcInfo.getAnnotationBearer();
85+
}
86+
87+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
package org.scijava.ops.matcher;
3131

32+
import java.lang.reflect.AnnotatedElement;
3233
import java.lang.reflect.Constructor;
3334
import java.lang.reflect.InvocationTargetException;
3435
import java.lang.reflect.Type;
@@ -141,6 +142,11 @@ public boolean isValid() {
141142
return validityException == null;
142143
}
143144

145+
@Override
146+
public AnnotatedElement getAnnotationBearer() {
147+
return opClass;
148+
}
149+
144150
// -- Object methods --
145151

146152
@Override

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
package org.scijava.ops.matcher;
3131

32+
import java.lang.reflect.AnnotatedElement;
3233
import java.lang.reflect.Field;
3334
import java.lang.reflect.Modifier;
3435
import java.lang.reflect.Type;
@@ -148,6 +149,11 @@ public ValidityException getValidityException() {
148149
public boolean isValid() {
149150
return validityException == null;
150151
}
152+
153+
@Override
154+
public AnnotatedElement getAnnotationBearer() {
155+
return field;
156+
}
151157

152158
// -- Object methods --
153159

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
package org.scijava.ops.matcher;
33

4+
import java.lang.reflect.AnnotatedElement;
45
import java.lang.reflect.Type;
56
import java.util.List;
67

@@ -52,4 +53,6 @@ default List<OpDependencyMember<?>> dependencies() {
5253
// TODO Consider if we really want to keep the following methods.
5354
boolean isValid();
5455
ValidityException getValidityException();
56+
57+
AnnotatedElement getAnnotationBearer();
5558
}

src/main/java/org/scijava/ops/transform/AdaptedOp.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11

22
package org.scijava.ops.transform;
33

4+
import java.lang.reflect.Type;
5+
6+
import org.scijava.ops.matcher.OpAdaptationInfo;
47
import org.scijava.ops.matcher.OpCandidate;
58
import org.scijava.ops.matcher.OpInfo;
69

710
/**
811
* Wrapper class to match a {@link OpTransformation} with a matching
912
* {@link OpCandidate}.
1013
*
11-
* @author David Kolb
1214
* @author Gabriel Selzer
1315
*/
1416
public class AdaptedOp {
1517

16-
Object op;
17-
OpInfo srcInfo;
18-
OpInfo adaptorInfo;
18+
private Object op;
19+
private Type type;
20+
private OpInfo srcInfo;
21+
private OpInfo adaptorInfo;
22+
23+
private OpInfo opInfo;
1924

20-
public AdaptedOp(Object op, OpInfo srcInfo, OpInfo adaptorInfo) {
25+
public AdaptedOp(Object op, Type type, OpInfo srcInfo, OpInfo adaptorInfo) {
2126
this.op = op;
27+
this.type = type;
2228
this.srcInfo = srcInfo;
2329
this.adaptorInfo= adaptorInfo;
30+
this.opInfo = new OpAdaptationInfo(srcInfo, this.type);
31+
2432
}
2533

2634
public Object op() {
@@ -34,6 +42,10 @@ public OpInfo srcInfo() {
3442
public OpInfo adaptorInfo() {
3543
return adaptorInfo;
3644
}
45+
46+
public OpInfo opInfo() {
47+
return opInfo;
48+
}
3749

3850
@Override
3951
public String toString() {

src/main/java/org/scijava/param/ParameterStructs.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.scijava.ops.FieldOpDependencyMember;
2525
import org.scijava.ops.OpDependency;
2626
import org.scijava.ops.OpDependencyMember;
27+
import org.scijava.ops.matcher.OpInfo;
2728
import org.scijava.struct.ItemIO;
2829
import org.scijava.struct.Member;
2930
import org.scijava.struct.Struct;
@@ -80,6 +81,12 @@ public static Struct structOf(final Field field)
8081
final List<Member<?>> items = parse(field);
8182
return () -> items;
8283
}
84+
85+
//TODO: Javadoc
86+
public static Struct structOf(final OpInfo opInfo, final Type newType) throws ValidityException {
87+
final List<Member<?>> items = parse(opInfo, newType);
88+
return () -> items;
89+
}
8390

8491
/**
8592
* Parses the specified functional class for @{@link Parameter} annotations. This consists of the following steps:
@@ -113,7 +120,7 @@ public static List<Member<?>> parse(final Class<?> type)
113120
// Parse class level (i.e., generic) @Parameter annotations.
114121
final Class<?> paramsClass = findParametersDeclaration(type);
115122
if (paramsClass != null) {
116-
parseFunctionalParameters(items, names, problems, paramsClass, type);
123+
parseFunctionalParameters(items, names, problems, paramsClass, type, false);
117124
}
118125

119126
// Parse field level @OpDependency annotations.
@@ -145,7 +152,23 @@ public static List<Member<?>> parse(final Field field) throws ValidityException
145152
final Type fieldType = Types.fieldType(field, c);
146153

147154
checkModifiers(field.toString() + ": ", problems, field.getModifiers(), false, Modifier.FINAL);
148-
parseFunctionalParameters(items, names, problems, field, fieldType);
155+
parseFunctionalParameters(items, names, problems, field, fieldType, false);
156+
157+
// Fail if there were any problems.
158+
if (!problems.isEmpty()) {
159+
throw new ValidityException(problems);
160+
}
161+
162+
return items;
163+
}
164+
165+
//TODO: Javadoc
166+
public static List<Member<?>> parse(final OpInfo opInfo, final Type newType) throws ValidityException {
167+
final ArrayList<Member<?>> items = new ArrayList<>();
168+
final ArrayList<ValidityProblem> problems = new ArrayList<>();
169+
final Set<String> names = new HashSet<>();
170+
171+
parseFunctionalParameters(items, names, problems, opInfo.getAnnotationBearer(), newType, true);
149172

150173
// Fail if there were any problems.
151174
if (!problems.isEmpty()) {
@@ -311,7 +334,7 @@ private static boolean resolveItemIOAuto(Parameter[] annotations, List<Functiona
311334
}
312335

313336
private static void parseFunctionalParameters(final ArrayList<Member<?>> items, final Set<String> names, final ArrayList<ValidityProblem> problems,
314-
AnnotatedElement annotationBearer, Type type) {
337+
AnnotatedElement annotationBearer, Type type, final boolean synthesizeAnnotations) {
315338
//Search for the functional method of 'type' and map its signature to ItemIO
316339
List<FunctionalMethodType> fmts = findFunctionalMethodTypes(type);
317340
if (fmts == null) {
@@ -322,7 +345,7 @@ private static void parseFunctionalParameters(final ArrayList<Member<?>> items,
322345
// Get parameter annotations (may not be present)
323346
Parameter[] annotations = AnnotationUtils.parameters(annotationBearer);
324347
// 'type' is annotated, resolve ItemIO.AUTO by matching it to the signature of the functional method
325-
if (annotations.length > 0) {
348+
if (annotations.length > 0 && !synthesizeAnnotations) {
326349
if (annotations.length != fmts.size()) {
327350
String fmtIOs = Arrays.deepToString(fmts.stream().map(fmt -> fmt.itemIO()).toArray(ItemIO[]::new));
328351
problems.add(new ValidityProblem("The number of inferred functional method types does not match "

0 commit comments

Comments
 (0)