How to call AbstractOp in plugin

Hey all,

I am updating a Fiji plugin and rewriting UnaryOutputOperation classes to AbstractOp classes. This is not an issue, my question is related to how to call the ops.

EDIT Sorry, did not read this page fully: there it is fully explained how to use Ops.



Ok I am still a bit unsure.

On the Adding new ops page, it says that the minimum setup requires an interface and an implementation (an Op and an AbstractOp). There you call the Op like this:

gcd = ops.op(GCD, 7, 10);

But in the create-new-op example, an AbstractOp called like this without an Op:

final ImageJ ij = new ImageJ();
// Run our op!
final Object narf = ij.op().run("narf", "Put some trousers on");

Is there a reason to use one over the other? The first one looks better for me because I do not have to use strings to identify my Op.

A second question:
If I update my my parent pom-scijava to version 16.1.0 to match Fiji, net.imagej.ops.Op is not found. Is this because the imagej-ops is based on pom-scijava version 14.0.0? Just trying to understand.

Which plugin?

The Ops developers tend to prefer the type-based invocations to the name-based ones, because the type-based ones are less error-prone. That is: the compiler will give you an error if you make a typo in the class name, but it won’t complain about a typo in a string.

That said, either one works.

Note that the CreateANewOp example is very minimal, and does not define a new op interface. While you can write ij.op().run(Narf.class, "whatever"), this ends up being a hardcoded call to the concrete Narf op itself, which is rather pointless since the Ops matcher will always select the Narf class. You may as well have just written plain old Java code at that point—e.g. narf = new Narf(); narf.input = "whatever";;. The point of the GCD interface is so that multiple GCD ops can be written, which operate on different sorts of input parameters, and/or optimize for performance in different cases. Supposing we are too lazy to create a Narf interface and then a DefaultNarf concrete implementation, using"narf", "...") here means that in theory, someone else could write a second MyBetterNarf and also write name = "narf" on it, and then the matcher will have options to work with.

Can you please share a pointer to your code? What really matters here are the dependencies of your project. To have access to net.imagej.ops.Ops, you of course need to have net.imagej:imagej-ops as a dependency of your project.

Nope, fortunately, these version numbers do not need to match precisely. If they did, we would have a huge problem as we would need to constantly update the pom-scijava parent version across hundreds of components.

The simplest way to think of pom-scijava is as a Bill of Materials—a “shopping list” of which component versions go together. The imagej-ops component itself depending on 14.0.0 means it inherits a BOM with versions older than the ones your component gets when it depends on 16.1.0. But that is usually not a problem. In any case, the fact that net.imagej.ops.Op cannot be found is not related to this version difference.

P.S. Have you looked at the Extending ImageJ: Ops Jupyter notebook yet? Future plan is to migrate the Adding new ops wiki page into that notebook.


MoMA and mmpreprocess. I work for and get help from @fjug and his team but this question seemed to be more general at first and therefore better suited for the forum.

Same here :slight_smile: Thanks for the explanation. I was hesitating what to use at this point in the code. The old version had a UnaryOutputOperation as a function argument and I was not sure if I should use a string and pass the op name or (as I am doing right now) passing a new Op instance. But that seems contradictory to what you just wrote about Ops.

EDIT net.imagej.ops.Op still cannot be found, this is the repo: and the error:

The type net.imagej.ops.Op cannot be resolved. It is indirectly referenced from required .class files
The project was not built since its build path is incomplete. Cannot find the class file for net.imagej.ops.Op. Fix the build path then try building this project

mvn package sais:

IOException while reading /home/random/.m2/repository/net/imagej/imagej-ops/0.38.0/imagej-ops-0.38.0.jar

but the file is readable…

Thanks for your time!

I removed the local file and ran mvn build again and that’s the response:

[INFO] Downloading:
[WARNING] Checksum validation failed: Checksum validation failed, expected d3f4d2ed4d64cdb9c2c99340c2d9db719f84075ed3f4d2ed4d64cdb9c2c99340c2d9db719f84075e but is d3f4d2ed4d64cdb9c2c99340c2d9db719f84075e for
[INFO] Downloaded: (1689 KB at 241.0 KB/sec)

The checksum is somehow duplicated…

:confused: The error is gone today. Version 16.1.0 is now working :slight_smile:

1 Like


If you have further difficulties and/or questions, happy to help discuss and troubleshoot in person next week when I am there. :smile: