Skip to content

Commit 217cd11

Browse files
gselzerctrueden
authored andcommitted
Test Therapi-Based Ops
1 parent 361c8be commit 217cd11

File tree

6 files changed

+155
-51
lines changed

6 files changed

+155
-51
lines changed

scijava/scijava-discovery-therapi/src/main/java/org/scijava/discovery/therapi/TherapiDiscoverer.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ public List<Discovery<AnnotatedElement>> elementsTaggedWith(String tagType) {
5656
tagType, javadocData);
5757
List<Discovery<AnnotatedElement>> taggedFields = discoverTaggedFields(
5858
tagType, javadocData);
59-
6059
// return concatenation of classes, methods, and fields.
6160
return Stream.of(taggedClasses, taggedMethods, taggedFields) //
6261
.flatMap(Collection::stream) //
@@ -199,8 +198,6 @@ private static List<String> getJarContent(String jarPath) throws IOException {
199198

200199
private Map<String, ?> itemsFromTag(String tagType, String tag) {
201200
String tagBody = tag.substring(tag.indexOf(tagType) + tagType.length()).trim();
202-
System.out.println("Parser: " + parser);
203-
System.out.println("Tag Body: " + tagBody);
204201
return parser.parse(tagBody.replaceAll("\\s+",""), true).asMap();
205202
}
206203

@@ -289,7 +286,7 @@ private List<Discovery<AnnotatedElement>> discoverTaggedClasses(
289286
Class<?> taggedClass = getClass(e.getValue());
290287
Optional<String> tag = getTag.apply(e.getKey(), tagType);
291288
if (tag.isEmpty()) return null;
292-
Supplier<Map<String, ?>> tagOptions = () -> itemsFromTag(tagType, e.getValue());
289+
Supplier<Map<String, ?>> tagOptions = () -> itemsFromTag(tagType, tag.get());
293290
return new Discovery<>(taggedClass, tagType, tagOptions);
294291
}
295292
catch (ClassNotFoundException exc) {

scijava/scijava-ops-engine/src/main/java/org/scijava/ops/engine/impl/OpCollectionInfoGenerator.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ public List<OpInfo> generateInfos() {
5858
final List<Method> methods = ClassUtils.getAnnotatedMethods(cls, OpMethod.class);
5959
for (final Method method: methods) {
6060
OpMethod annotation = method.getAnnotation(OpMethod.class);
61+
Class<?> opType = annotation.type();
6162
String unparsedOpNames = annotation.names();
6263
String[] parsedOpNames = OpUtils.parseOpNames(unparsedOpNames);
6364
Hints hints = formHints(method.getAnnotation(OpHints.class));
6465
double priority = annotation.priority();
65-
collectionInfos.add(new OpMethodInfo(method, version, hints, priority, parsedOpNames));
66+
collectionInfos.add(new OpMethodInfo(method, opType, version, hints, priority, parsedOpNames));
6667
}
6768
return collectionInfos;
6869
} catch (InstantiationException | IllegalAccessException exc) {

scijava/scijava-ops-engine/src/main/java/org/scijava/ops/engine/impl/TagBasedOpInfoGenerator.java

+53-34
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import java.util.Objects;
1111
import java.util.stream.Collectors;
1212

13+
import org.scijava.Context;
1314
import org.scijava.Priority;
1415
import org.scijava.discovery.Discoverer;
1516
import org.scijava.discovery.Discovery;
16-
import org.scijava.function.Functions;
1717
import org.scijava.log.LogService;
1818
import org.scijava.ops.api.OpInfo;
1919
import org.scijava.ops.api.OpInfoGenerator;
@@ -45,51 +45,64 @@ public class TagBasedOpInfoGenerator implements OpInfoGenerator {
4545
private final LogService log;
4646
private final List<Discoverer> discoverers;
4747

48-
public TagBasedOpInfoGenerator(LogService log, Discoverer... d) {
48+
public TagBasedOpInfoGenerator(final LogService log, Discoverer... d) {
4949
this.log = log;
5050
this.discoverers = Arrays.asList(d);
5151
}
5252

53-
Functions.Arity3<Class<?>, Double, String[], OpClassInfo> opClassGenerator = //
54-
(cls, priority, names) -> {
55-
String version = VersionUtils.getVersion(cls);
56-
return new OpClassInfo(cls, version, new DefaultHints(), priority, names);
57-
};
58-
59-
Functions.Arity3<Method, Double, String[], OpMethodInfo> opMethodGenerator = //
60-
(m, priority, names) -> {
61-
String version = VersionUtils.getVersion(m.getDeclaringClass());
62-
return new OpMethodInfo(m, version, new DefaultHints(), names);
63-
};
64-
65-
Functions.Arity3<Field, Double, String[], OpFieldInfo> opFieldGenerator = //
66-
(f, priority, names) -> {
67-
String version = VersionUtils.getVersion(f.getDeclaringClass());
68-
Object instance;
69-
try {
70-
instance = f.getDeclaringClass().getDeclaredConstructor().newInstance();
71-
}
72-
catch (InstantiationException | IllegalAccessException
73-
| IllegalArgumentException | InvocationTargetException
74-
| NoSuchMethodException | SecurityException exc)
53+
private OpInfo opClassGenerator(Class<?> cls, double priority,
54+
String[] names)
55+
{
56+
String version = VersionUtils.getVersion(cls);
57+
return new OpClassInfo(cls, version, new DefaultHints(), priority, names);
58+
}
59+
60+
private OpInfo opMethodGenerator(Method m, String opType, double priority,
61+
String[] names)
62+
{
63+
Class<?> cls;
64+
try {
65+
cls = Context.getClassLoader().loadClass(opType);
66+
}
67+
catch (ClassNotFoundException exc) {
68+
log.warn("Skipping method " + m + ": Cannot load Class" + opType);
69+
return null;
70+
}
71+
String version = VersionUtils.getVersion(m.getDeclaringClass());
72+
return new OpMethodInfo(m, cls, version, new DefaultHints(), priority,
73+
names);
74+
}
75+
76+
private OpInfo opFieldGenerator(Field f, double priority, String[] names) {
77+
String version = VersionUtils.getVersion(f.getDeclaringClass());
78+
Object instance;
79+
try {
80+
instance = f.getDeclaringClass().getDeclaredConstructor().newInstance();
81+
}
82+
catch (InstantiationException | IllegalAccessException
83+
| IllegalArgumentException | InvocationTargetException
84+
| NoSuchMethodException | SecurityException exc)
7585
{
76-
return null;
77-
}
78-
return new OpFieldInfo(instance, f, version, new DefaultHints(), names);
79-
};
86+
return null;
87+
}
88+
return new OpFieldInfo(instance, f, version, new DefaultHints(), priority,
89+
names);
90+
}
8091

8192
@Override
8293
public List<OpInfo> generateInfos() {
94+
try {
8395
List<OpInfo> infos = discoverers.stream() //
8496
.flatMap(d -> d.elementsTaggedWith(TAGTYPE).stream()) //
8597
.map(discovery -> {
8698
// Obtain op metadata
8799
String[] names;
100+
String opType;
88101
double priority;
89102

90103
try {
91104
names = getOpNames(discovery);
92-
System.out.println(names);
105+
opType = getOpType(discovery);
93106
priority = getOpPriority(discovery);
94107
}
95108
catch (IllegalArgumentException e) {
@@ -101,19 +114,23 @@ public List<OpInfo> generateInfos() {
101114
// Delegate to proper constructor
102115
AnnotatedElement e = discovery.discovery();
103116
if (e instanceof Class) {
104-
return opClassGenerator.apply((Class<?>) e, priority, names);
117+
return opClassGenerator((Class<?>) e, priority, names);
105118
}
106119
else if (e instanceof Method) {
107-
return opMethodGenerator.apply((Method) e, priority, names);
120+
return opMethodGenerator((Method) e, opType, priority, names);
108121
}
109122
else if (e instanceof Field) {
110-
return opFieldGenerator.apply((Field) e, priority, names);
123+
return opFieldGenerator((Field) e, priority, names);
111124
}
112125
else return null;
113126
}) //
114127
.filter(Objects::nonNull) //
115128
.collect(Collectors.toList());
116129
return infos;
130+
} catch(NullPointerException e) {
131+
e.printStackTrace();
132+
return null;
133+
}
117134
}
118135

119136
private String[] getOpNames(Discovery<AnnotatedElement> d) {
@@ -123,10 +140,8 @@ private String[] getOpNames(Discovery<AnnotatedElement> d) {
123140
throw new IllegalArgumentException("Op discovery " + d + " does not record any names!");
124141
}
125142
if (!names.isEmpty()) {
126-
System.out.println(names);
127143
return OpUtils.parseOpNames(names);
128144
}
129-
System.out.println(name);
130145
return OpUtils.parseOpNames(name);
131146
}
132147

@@ -135,4 +150,8 @@ private static double getOpPriority(Discovery<AnnotatedElement> d) {
135150
return priority.isEmpty() ? Priority.NORMAL : Double.parseDouble(priority);
136151
}
137152

153+
private static String getOpType(Discovery<AnnotatedElement> d) {
154+
return d.option("type");
155+
}
156+
138157
}

scijava/scijava-ops-engine/src/main/java/org/scijava/ops/engine/matcher/impl/OpMethodInfo.java

+7-9
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ public class OpMethodInfo implements OpInfo {
8989

9090
private final Hints hints;
9191

92-
public OpMethodInfo(final Method method, final String version, final Hints hints, final String... names) {
93-
this(method, version, hints, Priority.NORMAL, names);
92+
public OpMethodInfo(final Method method, final Class<?> opType, final String version, final Hints hints, final String... names) {
93+
this(method, opType, version, hints, Priority.NORMAL, names);
9494
}
9595

96-
public OpMethodInfo(final Method method, final String version, final Hints hints, final double priority, final String... names) {
96+
public OpMethodInfo(final Method method, final Class<?> opType, final String version, final Hints hints, final double priority, final String... names) {
9797
this.method = method;
9898
this.version = version;
9999
this.names = Arrays.asList(names);
@@ -103,10 +103,8 @@ public OpMethodInfo(final Method method, final String version, final Hints hints
103103
final List<ValidityProblem> problems = new ArrayList<>();
104104
checkModifiers(method, problems);
105105

106-
// determine the functional interface this Op should implement
107-
final OpMethod methodAnnotation = method.getAnnotation(OpMethod.class);
108-
this.opType = findOpType(method, methodAnnotation, problems);
109-
this.struct = generateStruct(method, problems, new MethodParameterMemberParser(), new MethodOpDependencyMemberParser());
106+
this.opType = findOpType(method, opType, problems);
107+
this.struct = generateStruct(method, problems, new MethodParameterMemberParser(opType), new MethodOpDependencyMemberParser());
110108

111109
validityException = problems.isEmpty() ? null : new ValidityException(
112110
problems);
@@ -124,11 +122,11 @@ private Struct generateStruct(Method m, List<ValidityProblem> problems,
124122
}
125123
}
126124

127-
private Type findOpType(Method m, OpMethod methodAnnotation,
125+
private Type findOpType(Method m, Class<?> opType,
128126
List<ValidityProblem> problems)
129127
{
130128
try {
131-
return OpMethodUtils.getOpMethodType(methodAnnotation.type(),
129+
return OpMethodUtils.getOpMethodType(opType,
132130
method);
133131
}
134132
catch (IllegalArgumentException e) {

scijava/scijava-ops-engine/src/main/java/org/scijava/ops/engine/struct/MethodParameterMemberParser.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
public class MethodParameterMemberParser implements
1717
MemberParser<Method, SynthesizedParameterMember<?>>
1818
{
19+
private final Class<?> opType;
20+
21+
/**
22+
* HACK: We need the opType here to determine the functional type.
23+
* @param opType
24+
*/
25+
public MethodParameterMemberParser(Class<?> opType) {
26+
this.opType = opType;
27+
}
1928

2029
@Override
2130
public List<SynthesizedParameterMember<?>> parse(Method source)
@@ -30,16 +39,15 @@ public List<SynthesizedParameterMember<?>> parse(Method source)
3039

3140
final ArrayList<SynthesizedParameterMember<?>> items = new ArrayList<>();
3241
final ArrayList<ValidityProblem> problems = new ArrayList<>();
33-
final OpMethod methodAnnotation = source.getAnnotation(OpMethod.class);
3442

3543
// Determine functional type
3644
Type functionalType;
3745
try {
38-
functionalType = OpMethodUtils.getOpMethodType(methodAnnotation.type(), source);
46+
functionalType = OpMethodUtils.getOpMethodType(opType, source);
3947
}
4048
catch (IllegalArgumentException e) {
4149
problems.add(new ValidityProblem(e.getMessage()));
42-
functionalType = Types.parameterizeRaw(methodAnnotation.type());
50+
functionalType = Types.parameterizeRaw(opType);
4351
}
4452

4553
// Parse method level @Parameter annotations.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.scijava.ops.engine.impl;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
import org.scijava.function.Producer;
6+
import org.scijava.ops.engine.AbstractTestEnvironment;
7+
8+
public class TherapiBasedOpTest extends AbstractTestEnvironment {
9+
10+
private static final String FIELD_STRING = "This OpField is discoverable using Therapi!";
11+
static final String CLASS_STRING = "This OpClass is discoverable using Therapi!";
12+
private static final String METHOD_STRING = "This OpMethod is discoverable using Therapi!";
13+
14+
/**
15+
* @implNote op names='test.therapiOpField'
16+
*/
17+
public final Producer<String> therapiFunction = () -> FIELD_STRING;
18+
19+
@Test
20+
public void therapiOpFieldTest() {
21+
String actual = ops.op("test.therapiOpField").input().outType(String.class).create();
22+
String expected = FIELD_STRING;
23+
Assert.assertEquals(expected, actual);
24+
}
25+
26+
@Test
27+
public void therapiOpClassTest() {
28+
String actual = ops.op("test.therapiOpClass").input().outType(String.class).create();
29+
String expected = CLASS_STRING;
30+
Assert.assertEquals(expected, actual);
31+
}
32+
33+
@Test
34+
public void therapiOpMethodTest() {
35+
String actual = ops.op("test.therapiOpMethod").input().outType(String.class).create();
36+
String expected = METHOD_STRING;
37+
Assert.assertEquals(expected, actual);
38+
}
39+
40+
/**
41+
* @implNote op names='test.therapiOpMethod',
42+
* type='org.scijava.function.Producer'
43+
* @return a {@link String}
44+
*/
45+
public static String therapiMethod() {
46+
return METHOD_STRING;
47+
}
48+
49+
private static final String HIGH_PRIORITY_STRING = "High Priority";
50+
private static final String LOW_PRIORITY_STRING = "Low Priority";
51+
52+
/**
53+
* @implNote op names='test.therapiPriority', priority='10.0'
54+
*/
55+
public final Producer<String> therapiHighPriorityFunction = () -> HIGH_PRIORITY_STRING;
56+
57+
/**
58+
* @implNote op names='test.therapiPriority', priority='1.0'
59+
*/
60+
public final Producer<String> therapiLowPriorityFunction = () -> LOW_PRIORITY_STRING;
61+
62+
@Test
63+
public void therapiOpFieldPriorityTest() {
64+
String actual = ops.op("test.therapiPriority").input().outType(String.class).create();
65+
String expected = HIGH_PRIORITY_STRING;
66+
Assert.assertEquals(expected, actual);
67+
}
68+
69+
}
70+
71+
/**
72+
* @implNote op names='test.therapiOpClass'
73+
*/
74+
class TherapiOpClass implements Producer<String> {
75+
76+
@Override
77+
public String create() {
78+
return TherapiBasedOpTest.CLASS_STRING;
79+
}
80+
81+
}

0 commit comments

Comments
 (0)