Skip to content

Commit

Permalink
Test Therapi-Based Ops
Browse files Browse the repository at this point in the history
  • Loading branch information
gselzer committed Oct 18, 2021
1 parent bc563ab commit db7141b
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ public List<Discovery<AnnotatedElement>> elementsTaggedWith(String tagType) {
tagType, javadocData);
List<Discovery<AnnotatedElement>> taggedFields = discoverTaggedFields(
tagType, javadocData);

// return concatenation of classes, methods, and fields.
return Stream.of(taggedClasses, taggedMethods, taggedFields) //
.flatMap(Collection::stream) //
Expand Down Expand Up @@ -199,8 +198,6 @@ private static List<String> getJarContent(String jarPath) throws IOException {

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

Expand Down Expand Up @@ -289,7 +286,7 @@ private List<Discovery<AnnotatedElement>> discoverTaggedClasses(
Class<?> taggedClass = getClass(e.getValue());
Optional<String> tag = getTag.apply(e.getKey(), tagType);
if (tag.isEmpty()) return null;
Supplier<Map<String, ?>> tagOptions = () -> itemsFromTag(tagType, e.getValue());
Supplier<Map<String, ?>> tagOptions = () -> itemsFromTag(tagType, tag.get());
return new Discovery<>(taggedClass, tagType, tagOptions);
}
catch (ClassNotFoundException exc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ public List<OpInfo> generateInfos() {
final List<Method> methods = ClassUtils.getAnnotatedMethods(cls, OpMethod.class);
for (final Method method: methods) {
OpMethod annotation = method.getAnnotation(OpMethod.class);
Class<?> opType = annotation.type();
String unparsedOpNames = annotation.names();
String[] parsedOpNames = OpUtils.parseOpNames(unparsedOpNames);
Hints hints = formHints(method.getAnnotation(OpHints.class));
double priority = annotation.priority();
collectionInfos.add(new OpMethodInfo(method, version, hints, priority, parsedOpNames));
collectionInfos.add(new OpMethodInfo(method, opType, version, hints, priority, parsedOpNames));
}
return collectionInfos;
} catch (InstantiationException | IllegalAccessException exc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import java.util.Objects;
import java.util.stream.Collectors;

import org.scijava.Context;
import org.scijava.Priority;
import org.scijava.discovery.Discoverer;
import org.scijava.discovery.Discovery;
import org.scijava.function.Functions;
import org.scijava.log.LogService;
import org.scijava.ops.api.OpInfo;
import org.scijava.ops.api.OpInfoGenerator;
Expand Down Expand Up @@ -45,51 +45,64 @@ public class TagBasedOpInfoGenerator implements OpInfoGenerator {
private final LogService log;
private final List<Discoverer> discoverers;

public TagBasedOpInfoGenerator(LogService log, Discoverer... d) {
public TagBasedOpInfoGenerator(final LogService log, Discoverer... d) {
this.log = log;
this.discoverers = Arrays.asList(d);
}

Functions.Arity3<Class<?>, Double, String[], OpClassInfo> opClassGenerator = //
(cls, priority, names) -> {
String version = VersionUtils.getVersion(cls);
return new OpClassInfo(cls, version, new DefaultHints(), priority, names);
};

Functions.Arity3<Method, Double, String[], OpMethodInfo> opMethodGenerator = //
(m, priority, names) -> {
String version = VersionUtils.getVersion(m.getDeclaringClass());
return new OpMethodInfo(m, version, new DefaultHints(), names);
};

Functions.Arity3<Field, Double, String[], OpFieldInfo> opFieldGenerator = //
(f, priority, names) -> {
String version = VersionUtils.getVersion(f.getDeclaringClass());
Object instance;
try {
instance = f.getDeclaringClass().getDeclaredConstructor().newInstance();
}
catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException exc)
private OpInfo opClassGenerator(Class<?> cls, double priority,
String[] names)
{
String version = VersionUtils.getVersion(cls);
return new OpClassInfo(cls, version, new DefaultHints(), priority, names);
}

private OpInfo opMethodGenerator(Method m, String opType, double priority,
String[] names)
{
Class<?> cls;
try {
cls = Context.getClassLoader().loadClass(opType);
}
catch (ClassNotFoundException exc) {
log.warn("Skipping method " + m + ": Cannot load Class" + opType);
return null;
}
String version = VersionUtils.getVersion(m.getDeclaringClass());
return new OpMethodInfo(m, cls, version, new DefaultHints(), priority,
names);
}

private OpInfo opFieldGenerator(Field f, double priority, String[] names) {
String version = VersionUtils.getVersion(f.getDeclaringClass());
Object instance;
try {
instance = f.getDeclaringClass().getDeclaredConstructor().newInstance();
}
catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException exc)
{
return null;
}
return new OpFieldInfo(instance, f, version, new DefaultHints(), names);
};
return null;
}
return new OpFieldInfo(instance, f, version, new DefaultHints(), priority,
names);
}

@Override
public List<OpInfo> generateInfos() {
try {
List<OpInfo> infos = discoverers.stream() //
.flatMap(d -> d.elementsTaggedWith(TAGTYPE).stream()) //
.map(discovery -> {
// Obtain op metadata
String[] names;
String opType;
double priority;

try {
names = getOpNames(discovery);
System.out.println(names);
opType = getOpType(discovery);
priority = getOpPriority(discovery);
}
catch (IllegalArgumentException e) {
Expand All @@ -101,19 +114,23 @@ public List<OpInfo> generateInfos() {
// Delegate to proper constructor
AnnotatedElement e = discovery.discovery();
if (e instanceof Class) {
return opClassGenerator.apply((Class<?>) e, priority, names);
return opClassGenerator((Class<?>) e, priority, names);
}
else if (e instanceof Method) {
return opMethodGenerator.apply((Method) e, priority, names);
return opMethodGenerator((Method) e, opType, priority, names);
}
else if (e instanceof Field) {
return opFieldGenerator.apply((Field) e, priority, names);
return opFieldGenerator((Field) e, priority, names);
}
else return null;
}) //
.filter(Objects::nonNull) //
.collect(Collectors.toList());
return infos;
} catch(NullPointerException e) {
e.printStackTrace();
return null;
}
}

private String[] getOpNames(Discovery<AnnotatedElement> d) {
Expand All @@ -123,10 +140,8 @@ private String[] getOpNames(Discovery<AnnotatedElement> d) {
throw new IllegalArgumentException("Op discovery " + d + " does not record any names!");
}
if (!names.isEmpty()) {
System.out.println(names);
return OpUtils.parseOpNames(names);
}
System.out.println(name);
return OpUtils.parseOpNames(name);
}

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

private static String getOpType(Discovery<AnnotatedElement> d) {
return d.option("type");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ public class OpMethodInfo implements OpInfo {

private final Hints hints;

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

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

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

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

private Type findOpType(Method m, OpMethod methodAnnotation,
private Type findOpType(Method m, Class<?> opType,
List<ValidityProblem> problems)
{
try {
return OpMethodUtils.getOpMethodType(methodAnnotation.type(),
return OpMethodUtils.getOpMethodType(opType,
method);
}
catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
public class MethodParameterMemberParser implements
MemberParser<Method, SynthesizedParameterMember<?>>
{
private final Class<?> opType;

/**
* HACK: We need the opType here to determine the functional type.
* @param opType
*/
public MethodParameterMemberParser(Class<?> opType) {
this.opType = opType;
}

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

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

// Determine functional type
Type functionalType;
try {
functionalType = OpMethodUtils.getOpMethodType(methodAnnotation.type(), source);
functionalType = OpMethodUtils.getOpMethodType(opType, source);
}
catch (IllegalArgumentException e) {
problems.add(new ValidityProblem(e.getMessage()));
functionalType = Types.parameterizeRaw(methodAnnotation.type());
functionalType = Types.parameterizeRaw(opType);
}

// Parse method level @Parameter annotations.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.scijava.ops.engine.impl;

import org.junit.Assert;
import org.junit.Test;
import org.scijava.function.Producer;
import org.scijava.ops.engine.AbstractTestEnvironment;

public class TherapiBasedOpTest extends AbstractTestEnvironment {

private static final String FIELD_STRING = "This OpField is discoverable using Therapi!";
static final String CLASS_STRING = "This OpClass is discoverable using Therapi!";
private static final String METHOD_STRING = "This OpMethod is discoverable using Therapi!";

/**
* @implNote op names='test.therapiOpField'
*/
public final Producer<String> therapiFunction = () -> FIELD_STRING;

@Test
public void therapiOpFieldTest() {
String actual = ops.op("test.therapiOpField").input().outType(String.class).create();
String expected = FIELD_STRING;
Assert.assertEquals(expected, actual);
}

@Test
public void therapiOpClassTest() {
String actual = ops.op("test.therapiOpClass").input().outType(String.class).create();
String expected = CLASS_STRING;
Assert.assertEquals(expected, actual);
}

@Test
public void therapiOpMethodTest() {
String actual = ops.op("test.therapiOpMethod").input().outType(String.class).create();
String expected = METHOD_STRING;
Assert.assertEquals(expected, actual);
}

/**
* @implNote op names='test.therapiOpMethod',
* type='org.scijava.function.Producer'
* @return a {@link String}
*/
public static String therapiMethod() {
return METHOD_STRING;
}

private static final String HIGH_PRIORITY_STRING = "High Priority";
private static final String LOW_PRIORITY_STRING = "Low Priority";

/**
* @implNote op names='test.therapiPriority', priority='10.0'
*/
public final Producer<String> therapiHighPriorityFunction = () -> HIGH_PRIORITY_STRING;

/**
* @implNote op names='test.therapiPriority', priority='1.0'
*/
public final Producer<String> therapiLowPriorityFunction = () -> LOW_PRIORITY_STRING;

@Test
public void therapiOpFieldPriorityTest() {
String actual = ops.op("test.therapiPriority").input().outType(String.class).create();
String expected = HIGH_PRIORITY_STRING;
Assert.assertEquals(expected, actual);
}

}

/**
* @implNote op names='test.therapiOpClass'
*/
class TherapiOpClass implements Producer<String> {

@Override
public String create() {
return TherapiBasedOpTest.CLASS_STRING;
}

}

0 comments on commit db7141b

Please sign in to comment.