Skip to content

Commit b57a28f

Browse files
gselzerwiedenm
andauthored
OpMethod support (#23)
* Add OpMethod annotation Signed by: Gabriel Selzer * Add OpMethodInfo Signed off by: Gabriel Selzer * Add Op method indexing Signed off by: Gabriel Selzer * Add simple Op method test Signed off by: Gabriel Selzer * restyle OpMethods * Add javassist dependency for OpMethods * OpMethods: first cut It's alive!!! Muahahaha * Create a suite of OpMethod Ops for testing * Test OpMethods for all functional types * Add tests for OpMethods with dependencies * Clean javassistOp * javassistOp: method params based on source params This allows us to be flexible on where we place our OpDependencies in our OpMethods Co-authored-by: Marcel Wiedenmann <Marcel.Wiedenmann@hotmail.com>
1 parent 5a99c86 commit b57a28f

20 files changed

Lines changed: 7580 additions & 28 deletions

scijava/scijava-ops/pom.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,19 +127,20 @@
127127
<artifactId>scijava-types</artifactId>
128128
<version>${project.version}</version>
129129
</dependency>
130-
131130
<!-- Third-party dependencies -->
132131
<dependency>
133132
<groupId>com.google.guava</groupId>
134133
<artifactId>guava</artifactId>
135134
</dependency>
136-
137135
<dependency>
138136
<groupId>io.leangen.geantyref</groupId>
139137
<artifactId>geantyref</artifactId>
140138
<version>${geantyref.version}</version>
141139
</dependency>
142-
140+
<dependency>
141+
<groupId>org.javassist</groupId>
142+
<artifactId>javassist</artifactId>
143+
</dependency>
143144
<!-- Test scope dependencies -->
144145
<dependency>
145146
<groupId>org.junit.jupiter</groupId>

scijava/scijava-ops/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@
2222

2323
requires org.scijava;
2424
requires org.scijava.types;
25+
requires javassist;
2526
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison and University of Konstanz.
7+
* %%
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright notice,
12+
* this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
* #L%
29+
*/
30+
31+
package org.scijava.ops;
32+
33+
import java.lang.reflect.Parameter;
34+
import java.lang.reflect.Type;
35+
36+
/**
37+
* @author Marcel Wiedenmann
38+
*/
39+
public class MethodParameterOpDependencyMember<T> extends
40+
AnnotatedOpDependencyMember<T>
41+
{
42+
43+
public MethodParameterOpDependencyMember(Parameter methodParameter,
44+
final Type parameterType, OpDependency annotation)
45+
{
46+
// NB: "Real" parameter name may or may not be available during runtime,
47+
// that is, the keys of instances of this class will likely be of the form:
48+
// arg0, arg1, etc.
49+
super(methodParameter.getName(), parameterType, annotation);
50+
}
51+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison and University of Konstanz.
7+
* %%
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright notice,
12+
* this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
* #L%
29+
*/
30+
31+
package org.scijava.ops;
32+
33+
import java.lang.annotation.ElementType;
34+
import java.lang.annotation.Retention;
35+
import java.lang.annotation.RetentionPolicy;
36+
import java.lang.annotation.Target;
37+
38+
@Retention(RetentionPolicy.RUNTIME)
39+
@Target(ElementType.METHOD)
40+
public @interface OpDependencies {
41+
42+
OpDependency[] value();
43+
44+
}

scijava/scijava-ops/src/main/java/org/scijava/ops/OpDependency.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package org.scijava.ops;
22

33
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Repeatable;
45
import java.lang.annotation.Retention;
56
import java.lang.annotation.RetentionPolicy;
67
import java.lang.annotation.Target;
78

89
/** Annotates a helper op as a field that should be auto injected.*/
910
@Retention(RetentionPolicy.RUNTIME)
10-
@Target(ElementType.FIELD)
11+
@Target({ ElementType.FIELD, ElementType.PARAMETER})
1112
public @interface OpDependency {
1213

1314
/** The name of the Op to inject. */
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison and University of Konstanz.
7+
* %%
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright notice,
12+
* this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
* #L%
29+
*/
30+
31+
package org.scijava.ops;
32+
33+
import java.lang.annotation.ElementType;
34+
import java.lang.annotation.Retention;
35+
import java.lang.annotation.RetentionPolicy;
36+
import java.lang.annotation.Target;
37+
38+
import org.scijava.Priority;
39+
40+
/**
41+
* @author Marcel Wiedenmann
42+
*/
43+
@Retention(RetentionPolicy.RUNTIME)
44+
@Target(ElementType.METHOD)
45+
public @interface OpMethod {
46+
47+
String names();
48+
49+
Class<?> type();
50+
51+
double priority() default Priority.NORMAL;
52+
53+
}

scijava/scijava-ops/src/main/java/org/scijava/ops/impl/DefaultOpEnvironment.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
package org.scijava.ops.impl;
3131

3232
import java.lang.reflect.Field;
33+
import java.lang.reflect.Method;
3334
import java.lang.reflect.Modifier;
3435
import java.lang.reflect.ParameterizedType;
3536
import java.lang.reflect.Type;
@@ -56,6 +57,7 @@
5657
import org.scijava.ops.OpEnvironment;
5758
import org.scijava.ops.OpField;
5859
import org.scijava.ops.OpInfo;
60+
import org.scijava.ops.OpMethod;
5961
import org.scijava.ops.OpUtils;
6062
import org.scijava.ops.core.Op;
6163
import org.scijava.ops.core.OpCollection;
@@ -68,6 +70,7 @@
6870
import org.scijava.ops.matcher.OpFieldInfo;
6971
import org.scijava.ops.matcher.OpMatcher;
7072
import org.scijava.ops.matcher.OpMatchingException;
73+
import org.scijava.ops.matcher.OpMethodInfo;
7174
import org.scijava.ops.matcher.OpRef;
7275
import org.scijava.ops.util.OpWrapper;
7376
import org.scijava.param.FunctionalMethodType;
@@ -528,7 +531,7 @@ private void initOpDirectory() {
528531
// Add Ops contained in an OpCollection
529532
for (final PluginInfo<OpCollection> pluginInfo : pluginService.getPluginsOfType(OpCollection.class)) {
530533
try {
531-
Class<? extends OpCollection> c = pluginInfo.loadClass();
534+
final Class<? extends OpCollection> c = pluginInfo.loadClass();
532535
final List<Field> fields = ClassUtils.getAnnotatedFields(c, OpField.class);
533536
Object instance = null;
534537
for (Field field : fields) {
@@ -539,6 +542,11 @@ private void initOpDirectory() {
539542
OpInfo opInfo = new OpFieldInfo(isStatic ? null : instance, field);
540543
addToOpIndex(opInfo, field.getAnnotation(OpField.class).names());
541544
}
545+
final List<Method> methods = ClassUtils.getAnnotatedMethods(c, OpMethod.class);
546+
for (final Method method: methods) {
547+
OpInfo opInfo = new OpMethodInfo(method);
548+
addToOpIndex(opInfo, method.getAnnotation(OpMethod.class).names());
549+
}
542550
} catch (InstantiableException | InstantiationException | IllegalAccessException exc) {
543551
log.error("Can't load class from plugin info: " + pluginInfo.toString(), exc);
544552
}

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

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,10 @@ public static boolean checkGenericAssignability(Type src,
243243
ParameterizedType dest, Map<TypeVariable<?>, Type> typeVarAssigns,
244244
boolean safeAssignability)
245245
{
246-
if (typeVarAssigns != null && !typeVarAssigns.isEmpty()) {
246+
if (typeVarAssigns == null) {
247+
typeVarAssigns = new HashMap<>();
248+
}
249+
else if (!typeVarAssigns.isEmpty()) {
247250
throw new IllegalArgumentException(
248251
"Expected empty typeVarAssigns but contained " + typeVarAssigns.size() +
249252
" entries");
@@ -260,12 +263,8 @@ public static boolean checkGenericAssignability(Type src,
260263
// assignability check.
261264
if (srcTypes.length == 0) return Types.isAssignable(src, dest);
262265
// if there are type parameters, do a more complicated assignability check.
263-
Map<TypeVariable<?>, TypeMapping> typeMappings = new HashMap<>();
264266
boolean result = checkGenericAssignability(srcTypes, destTypes, src, dest,
265-
typeMappings, safeAssignability);
266-
if (typeVarAssigns != null) {
267-
typeVarAssigns.putAll(new TypeVarAssigns(typeMappings));
268-
}
267+
typeVarAssigns, safeAssignability);
269268
return result;
270269
}
271270

@@ -334,7 +333,7 @@ public static boolean checkGenericAssignability(Type src, ParameterizedType dest
334333
* @param src the type for which assignment should be checked from
335334
* @param dest the parameterized type for which assignment should be checked
336335
* to
337-
* @param typeMappings the map of {@link TypeVariable}s to
336+
* @param typeVarAssigns the map of {@link TypeVariable}s to
338337
* {@link TypeMapping}s that would occur in this scenario
339338
* @param safeAssignability used to determine if we want to check if the
340339
* src->dest assignment would be safely assignable even though it
@@ -344,20 +343,18 @@ public static boolean checkGenericAssignability(Type src, ParameterizedType dest
344343
* java statement
345344
*/
346345
private static boolean checkGenericAssignability(Type[] srcTypes, Type[] destTypes, Type src, Type dest,
347-
Map<TypeVariable<?>, TypeMapping> typeMappings, boolean safeAssignability) {
346+
Map<TypeVariable<?>, Type> typeVarAssigns, boolean safeAssignability) {
348347
// if the number of type arguments does not match, the types can't be
349348
// assignable
350349
if (srcTypes.length != destTypes.length) {
351350
return false;
352351
}
353352

354-
TypeVarAssigns typeVarAssigns = new TypeVarAssigns(typeMappings);
355-
356353
try {
357354
// Try to infer type variables contained in the type arguments of
358355
// sry
359-
inferTypeVariables(srcTypes, destTypes, typeMappings);
360-
} catch (TypeInferenceException e) {
356+
inferTypeVariables(srcTypes, destTypes, typeVarAssigns);
357+
} catch (IllegalArgumentException e) {
361358
// types can't be inferred
362359
// TODO: Consider the situations in which it is okay that the type
363360
// variables cannot be inferred. For example, if we have a
@@ -464,11 +461,18 @@ private static Type[] mapVarToTypes(Type[] typesToMap, Map<TypeVariable<?>, Type
464461
* @param types - the types containing {@link TypeVariable}s
465462
* @param inferFroms - the types used to infer the {@link TypeVariable}s
466463
* within {@code types}
467-
* @param typeMappings - the mapping of {@link TypeVariable}s to
464+
* @param typeVarAssigns - the mapping of {@link TypeVariable}s to
468465
* {@link Type}s
469466
*/
470-
static void inferTypeVariables(Type[] types, Type[] inferFroms, Map<TypeVariable<?>, TypeMapping> typeMappings) {
471-
inferTypeVariables(types, inferFroms, typeMappings, true);
467+
public static void inferTypeVariables(Type[] types, Type[] inferFroms, Map<TypeVariable<?>, Type> typeVarAssigns) {
468+
Map<TypeVariable<?>, TypeMapping> typeMappings = new HashMap<>();
469+
try {
470+
inferTypeVariables(types, inferFroms, typeMappings, true);
471+
typeVarAssigns.putAll(new TypeVarAssigns(typeMappings));
472+
}
473+
catch (TypeInferenceException e) {
474+
throw new IllegalArgumentException(e);
475+
}
472476
}
473477

474478
private static void inferTypeVariables(Type[] types, Type[] inferFroms,
@@ -492,6 +496,22 @@ private static void inferTypeVariables(Type[] types, Type[] inferFroms,
492496
}
493497
}
494498

499+
/**
500+
* Tries to infer type vars contained in types from corresponding types from
501+
* inferFrom, putting them into the specified map. <b>When a
502+
* {@link TypeInferenceException} is thrown, the caller should assume that
503+
* some of the mappings within {@code typeMappings} are incorrect.</b>
504+
*
505+
* @param type
506+
* @param inferFrom
507+
* @param typeMappings
508+
*/
509+
static void inferTypeVariablesWithTypeMappings(Type type[], Type[] inferFrom,
510+
Map<TypeVariable<?>, TypeMapping> typeMappings)
511+
{
512+
inferTypeVariables(type, inferFrom, typeMappings, true);
513+
}
514+
495515
/**
496516
* Tries to infer type vars contained in types from corresponding types from
497517
* inferFrom, putting them into the specified map. <b>When a

0 commit comments

Comments
 (0)